From d4306149a07e51e866d31293f0f35a37633f88bb Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Mon, 29 Jan 2018 21:20:08 -0800 Subject: [PATCH 1/2] Updating the HWIntrinsic codegen to support marking LoadVector128 and LoadAlignedVector128 as contained. --- src/jit/codegenlinear.cpp | 4 ++ src/jit/emitxarch.cpp | 63 +++++++++++++++++ src/jit/emitxarch.h | 5 ++ src/jit/hwintrinsiccodegenxarch.cpp | 29 ++++++-- src/jit/hwintrinsiclistxarch.h | 6 +- src/jit/hwintrinsicxarch.cpp | 8 +++ src/jit/lower.h | 15 ++-- src/jit/lowerxarch.cpp | 105 ++++++++++++++++++++++++---- src/jit/lsrabuild.cpp | 5 ++ src/jit/namedintrinsiclist.h | 3 + src/jit/rationalize.cpp | 2 +- 11 files changed, 216 insertions(+), 29 deletions(-) diff --git a/src/jit/codegenlinear.cpp b/src/jit/codegenlinear.cpp index fb8b6b5fe008..eddec19c1f60 100644 --- a/src/jit/codegenlinear.cpp +++ b/src/jit/codegenlinear.cpp @@ -1297,6 +1297,10 @@ void CodeGen::genConsumeRegs(GenTree* tree) { genConsumeReg(tree->gtGetOp1()); } + else if (tree->OperIsHWIntrinsic()) + { + genConsumeReg(tree->gtGetOp1()); + } else { #ifdef FEATURE_SIMD diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 99dbce19a80c..e697b7bd5779 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -4009,6 +4009,28 @@ void emitter::emitIns_R_A_I(instruction ins, emitAttr attr, regNumber reg1, GenT emitCurIGsize += sz; } +void emitter::emitIns_R_AR_I(instruction ins, emitAttr attr, regNumber reg1, regNumber base, int offs, int ival) +{ + noway_assert(emitVerifyEncodable(ins, EA_SIZE(attr), reg1)); + assert(IsSSEOrAVXInstruction(ins)); + + instrDesc* id = emitNewInstrAmdCns(attr, offs, ival); + + id->idIns(ins); + id->idReg1(reg1); + + id->idInsFmt(IF_RRW_ARD_CNS); + id->idAddr()->iiaAddrMode.amBaseReg = base; + id->idAddr()->iiaAddrMode.amIndxReg = REG_NA; + + // Plus one for the 1-byte immediate (ival) + UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins)) + emitGetVexPrefixAdjustedSize(ins, attr, insCodeRM(ins)) + 1; + id->idCodeSize(sz); + + dispIns(id); + emitCurIGsize += sz; +} + void emitter::emitIns_R_C_I( instruction ins, emitAttr attr, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival) { @@ -4202,6 +4224,30 @@ void emitter::emitIns_R_R_A_I( dispIns(id); emitCurIGsize += sz; } + +void emitter::emitIns_R_R_AR_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs, int ival) +{ + assert(IsSSEOrAVXInstruction(ins)); + assert(IsThreeOperandAVXInstruction(ins)); + + instrDesc* id = emitNewInstrAmdCns(attr, offs, ival); + + id->idIns(ins); + id->idReg1(reg1); + id->idReg2(reg2); + + id->idInsFmt(IF_RWR_RRD_ARD_CNS); + id->idAddr()->iiaAddrMode.amBaseReg = base; + id->idAddr()->iiaAddrMode.amIndxReg = REG_NA; + + // Plus one for the 1-byte immediate (ival) + UNATIVE_OFFSET sz = emitInsSizeAM(id, insCodeRM(ins)) + emitGetVexPrefixAdjustedSize(ins, attr, insCodeRM(ins)) + 1; + id->idCodeSize(sz); + + dispIns(id); + emitCurIGsize += sz; +} #endif // !LEGACY_BACKEND void emitter::emitIns_R_R_C_I( @@ -5396,6 +5442,23 @@ void emitter::emitIns_SIMD_R_R_A_I( } } +void emitter::emitIns_SIMD_R_R_AR_I( + instruction ins, emitAttr attr, regNumber reg, regNumber reg1, regNumber base, int ival) +{ + if (UseVEXEncoding()) + { + emitIns_R_R_AR_I(ins, attr, reg, reg1, base, 0, ival); + } + else + { + if (reg1 != reg) + { + emitIns_R_R(INS_movaps, attr, reg, reg1); + } + emitIns_R_AR_I(ins, attr, reg, base, 0, ival); + } +} + void emitter::emitIns_SIMD_R_R_C_I( instruction ins, emitAttr attr, regNumber reg, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival) { diff --git a/src/jit/emitxarch.h b/src/jit/emitxarch.h index cca099cc72c0..85427674386a 100644 --- a/src/jit/emitxarch.h +++ b/src/jit/emitxarch.h @@ -386,6 +386,8 @@ void emitIns_R_A(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* i void emitIns_R_A_I(instruction ins, emitAttr attr, regNumber reg1, GenTreeIndir* indir, int ival); +void emitIns_R_AR_I(instruction ins, emitAttr attr, regNumber reg1, regNumber base, int offs, int ival); + void emitIns_R_C_I(instruction ins, emitAttr attr, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); void emitIns_R_S_I(instruction ins, emitAttr attr, regNumber reg1, int varx, int offs, int ival); @@ -405,6 +407,8 @@ void emitIns_R_R_R(instruction ins, emitAttr attr, regNumber reg1, regNumber reg #ifndef LEGACY_BACKEND void emitIns_R_R_A_I( instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, GenTreeIndir* indir, int ival, insFormat fmt); +void emitIns_R_R_AR_I( + instruction ins, emitAttr attr, regNumber reg1, regNumber reg2, regNumber base, int offs, int ival); #endif // !LEGACY_BACKEND void emitIns_R_R_C_I( @@ -475,6 +479,7 @@ void emitIns_AX_R(instruction ins, emitAttr attr, regNumber ireg, regNumber reg, #ifdef FEATURE_HW_INTRINSICS void emitIns_SIMD_R_R_AR(instruction ins, emitAttr attr, regNumber reg, regNumber reg1, regNumber base); void emitIns_SIMD_R_R_A_I(instruction ins, emitAttr attr, regNumber reg, regNumber reg1, GenTreeIndir* indir, int ival); +void emitIns_SIMD_R_R_AR_I(instruction ins, emitAttr attr, regNumber reg, regNumber reg1, regNumber base, int ival); void emitIns_SIMD_R_R_C_I( instruction ins, emitAttr attr, regNumber reg, regNumber reg1, CORINFO_FIELD_HANDLE fldHnd, int offs, int ival); void emitIns_SIMD_R_R_R_I(instruction ins, emitAttr attr, regNumber reg, regNumber reg1, regNumber reg2, int ival); diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp index e3e703e83db6..1aea1f1605d9 100644 --- a/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/jit/hwintrinsiccodegenxarch.cpp @@ -215,6 +215,9 @@ void CodeGen::genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins) if (op2->isContained() || op2->isUsedFromSpillTemp()) { + assert((Compiler::flagsOfHWIntrinsic(node->gtHWIntrinsicId) & HW_Flag_NoContainment) == 0); + assert(compiler->m_pLowering->IsContainableHWIntrinsicOp(node, op2) || op2->IsRegOptional()); + TempDsc* tmpDsc = nullptr; unsigned varNum = BAD_VAR_NUM; unsigned offset = (unsigned)-1; @@ -229,6 +232,11 @@ void CodeGen::genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins) compiler->tmpRlsTemp(tmpDsc); } + else if (op2->OperIsHWIntrinsic()) + { + emit->emitIns_SIMD_R_R_AR(ins, simdSize, targetReg, op1Reg, op2->gtGetOp1()->gtRegNum); + return; + } else if (op2->isIndir()) { GenTreeIndir* memIndir = op2->AsIndir(); @@ -242,7 +250,6 @@ void CodeGen::genHWIntrinsic_R_R_RM(GenTreeHWIntrinsic* node, instruction ins) offset = 0; // Ensure that all the GenTreeIndir values are set to their defaults. - assert(memBase->gtRegNum == REG_NA); assert(!memIndir->HasIndex()); assert(memIndir->Scale() == 1); assert(memIndir->Offset() == 0); @@ -310,6 +317,7 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) regNumber targetReg = node->gtRegNum; GenTree* op1 = node->gtGetOp1(); GenTree* op2 = node->gtGetOp2(); + emitAttr simdSize = (emitAttr)(node->gtSIMDSize); int ival = Compiler::ivalOfHWIntrinsic(node->gtHWIntrinsicId); emitter* emit = getEmitter(); @@ -323,6 +331,9 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) if (op2->isContained() || op2->isUsedFromSpillTemp()) { + assert((Compiler::flagsOfHWIntrinsic(node->gtHWIntrinsicId) & HW_Flag_NoContainment) == 0); + assert(compiler->m_pLowering->IsContainableHWIntrinsicOp(node, op2) || op2->IsRegOptional()); + TempDsc* tmpDsc = nullptr; unsigned varNum = BAD_VAR_NUM; unsigned offset = (unsigned)-1; @@ -337,6 +348,11 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) compiler->tmpRlsTemp(tmpDsc); } + else if (op2->OperIsHWIntrinsic()) + { + emit->emitIns_SIMD_R_R_AR_I(ins, simdSize, targetReg, op1Reg, op2->gtGetOp1()->gtRegNum, ival); + return; + } else if (op2->isIndir()) { GenTreeIndir* memIndir = op2->AsIndir(); @@ -350,7 +366,6 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) offset = 0; // Ensure that all the GenTreeIndir values are set to their defaults. - assert(memBase->gtRegNum == REG_NA); assert(!memIndir->HasIndex()); assert(memIndir->Scale() == 1); assert(memIndir->Offset() == 0); @@ -360,14 +375,14 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) case GT_CLS_VAR_ADDR: { - emit->emitIns_SIMD_R_R_C_I(ins, emitTypeSize(targetType), targetReg, op1Reg, - memBase->gtClsVar.gtClsVarHnd, 0, ival); + emit->emitIns_SIMD_R_R_C_I(ins, simdSize, targetReg, op1Reg, memBase->gtClsVar.gtClsVarHnd, 0, + ival); return; } default: { - emit->emitIns_SIMD_R_R_A_I(ins, emitTypeSize(targetType), targetReg, op1Reg, memIndir, ival); + emit->emitIns_SIMD_R_R_A_I(ins, simdSize, targetReg, op1Reg, memIndir, ival); return; } } @@ -405,11 +420,11 @@ void CodeGen::genHWIntrinsic_R_R_RM_I(GenTreeHWIntrinsic* node, instruction ins) assert((varNum != BAD_VAR_NUM) || (tmpDsc != nullptr)); assert(offset != (unsigned)-1); - emit->emitIns_SIMD_R_R_S_I(ins, emitTypeSize(targetType), targetReg, op1Reg, varNum, offset, ival); + emit->emitIns_SIMD_R_R_S_I(ins, simdSize, targetReg, op1Reg, varNum, offset, ival); } else { - emit->emitIns_SIMD_R_R_R_I(ins, emitTypeSize(targetType), targetReg, op1Reg, op2->gtRegNum, ival); + emit->emitIns_SIMD_R_R_R_I(ins, simdSize, targetReg, op1Reg, op2->gtRegNum, ival); } } diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index 9237f1a17742..18b0bc94bb38 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -176,7 +176,7 @@ HARDWARE_INTRINSIC(SSE41_BlendVariable, "BlendVaria // SSE42 Intrinsics HARDWARE_INTRINSIC(SSE42_IsSupported, "get_IsSupported", SSE42, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(SSE42_Crc32, "Crc32", SSE42, -1, 0, 2, {INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(SSE42_Crc32, "Crc32", SSE42, -1, 0, 2, {INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_crc32, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) // AVX Intrinsics // TODO-XArch When implementing SetZeroVector256 add case to switch table in gentree.cpp @@ -207,14 +207,14 @@ HARDWARE_INTRINSIC(FMA_IsSupported, "get_IsSupp // LZCNT Intrinsics HARDWARE_INTRINSIC(LZCNT_IsSupported, "get_IsSupported", LZCNT, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(LZCNT_LeadingZeroCount, "LeadingZeroCount", LZCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_lzcnt, INS_invalid, INS_lzcnt, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) // PCLMULQDQ Intrinsics HARDWARE_INTRINSIC(PCLMULQDQ_IsSupported, "get_IsSupported", PCLMULQDQ, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) // POPCNT Intrinsics HARDWARE_INTRINSIC(POPCNT_IsSupported, "get_IsSupported", POPCNT, -1, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IsSupportedProperty, HW_Flag_NoFlag) -HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFlag) +HARDWARE_INTRINSIC(POPCNT_PopCount, "PopCount", POPCNT, -1, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_popcnt, INS_invalid, INS_popcnt, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed) #endif // FEATURE_HW_INTRINSIC #undef HARDWARE_INTRINSIC diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp index 88b0eda793c2..5f16dd00be15 100644 --- a/src/jit/hwintrinsicxarch.cpp +++ b/src/jit/hwintrinsicxarch.cpp @@ -420,6 +420,7 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, int numArgs = sig->numArgs; var_types retType = JITtype2varType(sig->retType); var_types baseType = TYP_UNKNOWN; + if (retType == TYP_STRUCT && featureSIMD) { unsigned int sizeBytes; @@ -482,6 +483,13 @@ GenTree* Compiler::impHWIntrinsic(NamedIntrinsic intrinsic, } } + if ((flags & HW_Flag_NoFloatingPointUsed) == 0) + { + // Set `compFloatingPointUsed` to cover the scenario where an intrinsic is being on SIMD fields, but + // where no SIMD local vars are in use. This is the same logic as is used for FEATURE_SIMD. + compFloatingPointUsed = true; + } + // table-driven importer of simple intrinsics if (impIsTableDrivenHWIntrinsic(category, flags)) { diff --git a/src/jit/lower.h b/src/jit/lower.h index 2f7d3bd9efa5..0d298e0a52fa 100644 --- a/src/jit/lower.h +++ b/src/jit/lower.h @@ -319,11 +319,6 @@ class Lowering : public Phase public: static bool IndirsAreEquivalent(GenTree* pTreeA, GenTree* pTreeB); -private: - static bool NodesAreEquivalentLeaves(GenTree* candidate, GenTree* storeInd); - - bool AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index); - // return true if 'childNode' is an immediate that can be contained // by the 'parentNode' (i.e. folded into an instruction) // for example small enough and non-relocatable @@ -335,6 +330,16 @@ class Lowering : public Phase return m_lsra->isContainableMemoryOp(node); } +#ifdef FEATURE_HW_INTRINSICS + // Return true if 'node' is a containable HWIntrinsic op. + bool IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node); +#endif // FEATURE_HW_INTRINSICS + +private: + static bool NodesAreEquivalentLeaves(GenTree* candidate, GenTree* storeInd); + + bool AreSourcesPossiblyModifiedLocals(GenTree* addr, GenTree* base, GenTree* index); + // Makes 'childNode' contained in the 'parentNode' void MakeSrcContained(GenTree* parentNode, GenTree* childNode); diff --git a/src/jit/lowerxarch.cpp b/src/jit/lowerxarch.cpp index d212d8616344..559d0c7960da 100644 --- a/src/jit/lowerxarch.cpp +++ b/src/jit/lowerxarch.cpp @@ -2296,6 +2296,65 @@ void Lowering::ContainCheckSIMD(GenTreeSIMD* simdNode) #endif // FEATURE_SIMD #ifdef FEATURE_HW_INTRINSICS +//---------------------------------------------------------------------------------------------- +// IsContainableHWIntrinsicOp: Return true if 'node' is a containable HWIntrinsic op. +// +// Arguments: +// containingNode - The hardware intrinsic node which contains 'node' +// node - The node to check +// +// Return Value: +// true if 'node' is a containable hardware intrinsic node; otherwise, false. +// +bool Lowering::IsContainableHWIntrinsicOp(GenTreeHWIntrinsic* containingNode, GenTree* node) +{ + if (!node->OperIsHWIntrinsic()) + { + // non-HWIntrinsic nodes are assumed to be unaligned loads, which are only + // supported by the VEX encoding. + return comp->canUseVexEncoding() && IsContainableMemoryOp(node); + } + + bool isContainable = false; + + // TODO-XArch: Update this to be table driven, if possible. + + NamedIntrinsic containingIntrinsicID = containingNode->gtHWIntrinsicId; + HWIntrinsicCategory containingCategory = Compiler::categoryOfHWIntrinsic(containingIntrinsicID); + NamedIntrinsic intrinsicID = node->AsHWIntrinsic()->gtHWIntrinsicId; + + switch (intrinsicID) + { + // Non-VEX encoded instructions require aligned memory ops, so we can fold them. + // However, we cannot do the same for the VEX-encoding as it changes an observable + // side-effect and may mask an Access Violation that would otherwise occur. + case NI_SSE_LoadAlignedVector128: + isContainable = (containingCategory == HW_Category_SimpleSIMD) && !comp->canUseVexEncoding(); + break; + + // Only fold a scalar load into a SIMD scalar intrinsic to ensure the number of bits + // read remains the same. Likewise, we can't fold a larger load into a SIMD scalar + // intrinsic as that would read fewer bits that requested. + case NI_SSE_LoadScalarVector128: + isContainable = (containingCategory == HW_Category_SIMDScalar); + break; + + // VEX encoding supports unaligned memory ops, so we can fold them + case NI_SSE_LoadVector128: + isContainable = (containingCategory == HW_Category_SimpleSIMD) && comp->canUseVexEncoding(); + break; + + default: + return false; + } + + // For containable nodes, the base type of the original node and the base type of the contained node + // should be the same. This helps ensure we aren't reading too many or too few bits. + assert(!isContainable || (containingNode->gtSIMDBaseType == node->AsHWIntrinsic()->gtSIMDBaseType)); + + return isContainable; +} + //---------------------------------------------------------------------------------------------- // ContainCheckHWIntrinsic: Perform containment analysis for a hardware intrinsic node. // @@ -2311,25 +2370,45 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) GenTree* op1 = node->gtGetOp1(); GenTree* op2 = node->gtGetOp2(); + if ((flags & HW_Flag_NoContainment) != 0) + { + // Exit early if containment isn't supported + return; + } + // TODO-XArch-CQ: Non-VEX encoded instructions can have both ops contained - // TODO-XArch-CQ: Non-VEX encoded instructions require memory ops to be aligned - if (comp->canUseVexEncoding() && numArgs == 2 && (flags & HW_Flag_NoContainment) == 0 && - category == HW_Category_SimpleSIMD) + if (numArgs == 2) { - if (IsContainableMemoryOp(op2)) + switch (category) { - MakeSrcContained(node, op2); - } - else - { - // TODO-XArch-CQ: Commutative operations can have op1 be contained - op2->SetRegOptional(); + case HW_Category_SimpleSIMD: + case HW_Category_SIMDScalar: + if (IsContainableHWIntrinsicOp(node, op2)) + { + MakeSrcContained(node, op2); + } + else if (((flags & HW_Flag_Commutative) != 0) && IsContainableHWIntrinsicOp(node, op1)) + { + MakeSrcContained(node, op1); + + // Swap the operands here to make the containment checks in codegen significantly simpler + node->gtOp1 = op2; + node->gtOp2 = op1; + } + else if (comp->canUseVexEncoding()) + { + // We can only mark as reg optional when using the VEX encoding + // since that supports unaligned mem operands and non-VEX doesn't + op2->SetRegOptional(); + } + break; + + default: + break; } } - - // TODO - change to all IMM intrinsics - if (intrinsicID == NI_SSE_Shuffle) + else if (intrinsicID == NI_SSE_Shuffle) // TODO - change to all IMM intrinsics { assert(op1->OperIsList()); GenTree* op3 = op1->AsArgList()->Rest()->Rest()->Current(); diff --git a/src/jit/lsrabuild.cpp b/src/jit/lsrabuild.cpp index 0d3cccb6b32c..f3f019d8748c 100644 --- a/src/jit/lsrabuild.cpp +++ b/src/jit/lsrabuild.cpp @@ -2614,6 +2614,11 @@ int LinearScan::GetOperandInfo(GenTree* node) const unsigned srcCount = GetIndirInfo(node->AsIndir()); return srcCount; } + if (node->OperIsHWIntrinsic()) + { + appendLocationInfoToList(node->gtGetOp1()); + return 1; + } return 0; } diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h index a6edd867b17d..3bc85976d13d 100644 --- a/src/jit/namedintrinsiclist.h +++ b/src/jit/namedintrinsiclist.h @@ -77,6 +77,9 @@ enum HWIntrinsicFlag : unsigned int // Select base type using argument type HW_Flag_BaseTypeFromArg = 0x400, + + // Indicates compFloatingPointUsed does not need to be set. + HW_Flag_NoFloatingPointUsed = 0x800 }; inline HWIntrinsicFlag operator|(HWIntrinsicFlag c1, HWIntrinsicFlag c2) diff --git a/src/jit/rationalize.cpp b/src/jit/rationalize.cpp index 3696f40f7cc2..b40abd67919c 100644 --- a/src/jit/rationalize.cpp +++ b/src/jit/rationalize.cpp @@ -848,7 +848,7 @@ Compiler::fgWalkResult Rationalizer::RewriteNode(GenTree** useEdge, ArrayStackisAddrOfSIMDType(node->AsBlk()->Addr())) { GenTree* dataSrc = parent->gtGetOp2(); - if (!dataSrc->IsLocal() && (dataSrc->OperGet() != GT_SIMD)) + if (!dataSrc->IsLocal() && (dataSrc->OperGet() != GT_SIMD) && (!dataSrc->OperIsHWIntrinsic())) { noway_assert(dataSrc->OperIsIndir()); keepBlk = !comp->isAddrOfSIMDType(dataSrc->AsIndir()->Addr()); From 51bd59d37cae096c20a11f460ef535eb7240741b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 3 Feb 2018 00:13:27 -0800 Subject: [PATCH 2/2] Updating the templated x86 hwintrinsic tests to validate Load and LoadAligned --- .../JIT/HardwareIntrinsics/X86/Avx2/Add.cs | 324 ------------------ .../X86/Shared/BooleanCmpOpTest.template | 195 ++++++++--- .../X86/Shared/BooleanCmpOpTest_DataTable.cs | 35 +- .../X86/Shared/GenerateTests.csx | 166 ++++----- .../X86/Shared/SimpleBinOpTest.template | 219 ++++++++---- .../SimpleBinOpTest_DataTable_Aligned.cs | 62 ++++ .../HardwareIntrinsics/X86/Sse/Add.Single.cs | 137 +++++++- .../X86/Sse/AddScalar.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/And.Single.cs | 137 +++++++- .../X86/Sse/AndNot.Single.cs | 137 +++++++- .../X86/Sse/CompareEqual.Single.cs | 137 +++++++- .../Sse/CompareEqualOrderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareEqualScalar.Single.cs | 137 +++++++- .../Sse/CompareEqualUnorderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareGreaterThan.Single.cs | 137 +++++++- .../Sse/CompareGreaterThanOrEqual.Single.cs | 137 +++++++- ...eGreaterThanOrEqualOrderedScalar.Single.cs | 115 ++++++- .../CompareGreaterThanOrEqualScalar.Single.cs | 137 +++++++- ...reaterThanOrEqualUnorderedScalar.Single.cs | 115 ++++++- .../CompareGreaterThanOrderedScalar.Single.cs | 115 ++++++- .../Sse/CompareGreaterThanScalar.Single.cs | 137 +++++++- ...ompareGreaterThanUnorderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareLessThan.Single.cs | 137 +++++++- .../X86/Sse/CompareLessThanOrEqual.Single.cs | 137 +++++++- ...pareLessThanOrEqualOrderedScalar.Single.cs | 115 ++++++- .../CompareLessThanOrEqualScalar.Single.cs | 137 +++++++- ...reLessThanOrEqualUnorderedScalar.Single.cs | 115 ++++++- .../CompareLessThanOrderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareLessThanScalar.Single.cs | 137 +++++++- .../CompareLessThanUnorderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareNotEqual.Single.cs | 137 +++++++- .../CompareNotEqualOrderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareNotEqualScalar.Single.cs | 137 +++++++- .../CompareNotEqualUnorderedScalar.Single.cs | 115 ++++++- .../X86/Sse/CompareNotGreaterThan.Single.cs | 137 +++++++- .../CompareNotGreaterThanOrEqual.Single.cs | 137 +++++++- ...mpareNotGreaterThanOrEqualScalar.Single.cs | 137 +++++++- .../Sse/CompareNotGreaterThanScalar.Single.cs | 137 +++++++- .../X86/Sse/CompareNotLessThan.Single.cs | 137 +++++++- .../Sse/CompareNotLessThanOrEqual.Single.cs | 137 +++++++- .../CompareNotLessThanOrEqualScalar.Single.cs | 137 +++++++- .../Sse/CompareNotLessThanScalar.Single.cs | 137 +++++++- .../X86/Sse/CompareOrdered.Single.cs | 137 +++++++- .../X86/Sse/CompareOrderedScalar.Single.cs | 137 +++++++- .../X86/Sse/CompareUnordered.Single.cs | 137 +++++++- .../X86/Sse/CompareUnorderedScalar.Single.cs | 137 +++++++- .../X86/Sse/Divide.Single.cs | 137 +++++++- .../X86/Sse/DivideScalar.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/Max.Single.cs | 137 +++++++- .../X86/Sse/MaxScalar.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/Min.Single.cs | 137 +++++++- .../X86/Sse/MinScalar.Single.cs | 137 +++++++- .../X86/Sse/Multiply.Single.cs | 137 +++++++- .../X86/Sse/MultiplyScalar.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/Or.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/Sse_r.csproj | 2 +- .../HardwareIntrinsics/X86/Sse/Sse_ro.csproj | 2 +- .../X86/Sse/Subtract.Single.cs | 137 +++++++- .../X86/Sse/SubtractScalar.Single.cs | 137 +++++++- .../HardwareIntrinsics/X86/Sse/Xor.Single.cs | 137 +++++++- 60 files changed, 6419 insertions(+), 1446 deletions(-) delete mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable_Aligned.cs diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.cs deleted file mode 100644 index 31614a08ecce..000000000000 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.cs +++ /dev/null @@ -1,324 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -// See the LICENSE file in the project root for more information. -// - -using System; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics.X86; -using System.Runtime.Intrinsics; - -namespace IntelHardwareIntrinsicTest -{ - static class Program - { - const int Pass = 100; - const int Fail = 0; - - static unsafe int Main(string[] args) - { - int testResult = Pass; - - if (Avx2.IsSupported) - { - using (TestTable intTable = new TestTable(new int[8] { 1, -5, 100, 0, 1, -5, 100, 0 }, new int[8] { 22, -1, -50, 0, 22, -1, -50, 0 }, new int[8])) - using (TestTable longTable = new TestTable(new long[4] { 1, -5, 100, 0 }, new long[4] { 22, -1, -50, 0 }, new long[4])) - using (TestTable uintTable = new TestTable(new uint[8] { 1, 5, 100, 0, 1, 5, 100, 0 }, new uint[8] { 22, 1, 50, 0, 22, 1, 50, 0 }, new uint[8])) - using (TestTable ulongTable = new TestTable(new ulong[4] { 1, 5, 100, 0 }, new ulong[4] { 22, 1, 50, 0 }, new ulong[4])) - using (TestTable shortTable = new TestTable(new short[16] { 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0 }, new short[16] { 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0 }, new short[16])) - using (TestTable ushortTable = new TestTable(new ushort[16] { 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0 }, new ushort[16] { 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0 }, new ushort[16])) - using (TestTable sbyteTable = new TestTable(new sbyte[32] { 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0 }, new sbyte[32] { 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0 }, new sbyte[32])) - using (TestTable byteTable = new TestTable(new byte[32] { 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0 }, new byte[32] { 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0 }, new byte[32])) - { - - var vi1 = Unsafe.Read>(intTable.inArray1Ptr); - var vi2 = Unsafe.Read>(intTable.inArray2Ptr); - var vi3 = Avx2.Add(vi1, vi2); - Unsafe.Write(intTable.outArrayPtr, vi3); - - if (!intTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on int:"); - foreach (var item in intTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vi3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vi1.GetType(), vi2.GetType() }).Invoke(null, new object[] { vi1, vi2 }); - Unsafe.Write(intTable.outArrayPtr, vi3); - - if (!intTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on int:"); - foreach (var item in intTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vl1 = Unsafe.Read>(longTable.inArray1Ptr); - var vl2 = Unsafe.Read>(longTable.inArray2Ptr); - var vl3 = Avx2.Add(vl1, vl2); - Unsafe.Write(longTable.outArrayPtr, vl3); - - if (!longTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on long:"); - foreach (var item in longTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vl3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vl1.GetType(), vl2.GetType() }).Invoke(null, new object[] { vl1, vl2 }); - Unsafe.Write(longTable.outArrayPtr, vl3); - - if (!longTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on long:"); - foreach (var item in longTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vui1 = Unsafe.Read>(uintTable.inArray1Ptr); - var vui2 = Unsafe.Read>(uintTable.inArray2Ptr); - var vui3 = Avx2.Add(vui1, vui2); - Unsafe.Write(uintTable.outArrayPtr, vui3); - - if (!uintTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on uint:"); - foreach (var item in uintTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vui3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vui1.GetType(), vui2.GetType() }).Invoke(null, new object[] { vui1, vui2 }); - Unsafe.Write(uintTable.outArrayPtr, vui3); - - if (!uintTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on uint:"); - foreach (var item in uintTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vul1 = Unsafe.Read>(ulongTable.inArray1Ptr); - var vul2 = Unsafe.Read>(ulongTable.inArray2Ptr); - var vul3 = Avx2.Add(vul1, vul2); - Unsafe.Write(ulongTable.outArrayPtr, vul3); - - if (!ulongTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on ulong:"); - foreach (var item in ulongTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vul3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vul1.GetType(), vul2.GetType() }).Invoke(null, new object[] { vul1, vul2 }); - Unsafe.Write(ulongTable.outArrayPtr, vul3); - - if (!ulongTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on ulong:"); - foreach (var item in ulongTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vs1 = Unsafe.Read>(shortTable.inArray1Ptr); - var vs2 = Unsafe.Read>(shortTable.inArray2Ptr); - var vs3 = Avx2.Add(vs1, vs2); - Unsafe.Write(shortTable.outArrayPtr, vs3); - - if (!shortTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on short:"); - foreach (var item in shortTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vs3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vs1.GetType(), vs2.GetType() }).Invoke(null, new object[] { vs1, vs2 }); - Unsafe.Write(shortTable.outArrayPtr, vs3); - - if (!shortTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on short:"); - foreach (var item in shortTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vus1 = Unsafe.Read>(ushortTable.inArray1Ptr); - var vus2 = Unsafe.Read>(ushortTable.inArray2Ptr); - var vus3 = Avx2.Add(vus1, vus2); - Unsafe.Write(ushortTable.outArrayPtr, vus3); - - if (!ushortTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on ushort:"); - foreach (var item in ushortTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vus3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vus1.GetType(), vus2.GetType() }).Invoke(null, new object[] { vus1, vus2 }); - Unsafe.Write(ushortTable.outArrayPtr, vus3); - - if (!ushortTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on ushort:"); - foreach (var item in ushortTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vsb1 = Unsafe.Read>(sbyteTable.inArray1Ptr); - var vsb2 = Unsafe.Read>(sbyteTable.inArray2Ptr); - var vsb3 = Avx2.Add(vsb1, vsb2); - Unsafe.Write(sbyteTable.outArrayPtr, vsb3); - - if (!sbyteTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on sbyte:"); - foreach (var item in sbyteTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vsb3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vsb1.GetType(), vsb2.GetType() }).Invoke(null, new object[] { vsb1, vsb2 }); - Unsafe.Write(sbyteTable.outArrayPtr, vsb3); - - if (!sbyteTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on sbyte:"); - foreach (var item in sbyteTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - var vb1 = Unsafe.Read>(byteTable.inArray1Ptr); - var vb2 = Unsafe.Read>(byteTable.inArray2Ptr); - var vb3 = Avx2.Add(vb1, vb2); - Unsafe.Write(byteTable.outArrayPtr, vb3); - - if (!byteTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed on byte:"); - foreach (var item in byteTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - - vb3 = (Vector256)typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { vb1.GetType(), vb2.GetType() }).Invoke(null, new object[] { vb1, vb2 }); - Unsafe.Write(byteTable.outArrayPtr, vb3); - - if (!byteTable.CheckResult((x, y, z) => x + y == z)) - { - Console.WriteLine("AVX2 Add failed via reflection on byte:"); - foreach (var item in byteTable.outArray) - { - Console.Write(item + ", "); - } - Console.WriteLine(); - testResult = Fail; - } - } - } - - return testResult; - } - - public unsafe struct TestTable : IDisposable where T : struct - { - public T[] inArray1; - public T[] inArray2; - public T[] outArray; - - public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); - public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer(); - public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); - - GCHandle inHandle1; - GCHandle inHandle2; - GCHandle outHandle; - public TestTable(T[] a, T[] b, T[] c) - { - this.inArray1 = a; - this.inArray2 = b; - this.outArray = c; - - inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); - inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned); - outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); - } - public bool CheckResult(Func check) - { - for (int i = 0; i < inArray1.Length; i++) - { - if (!check(inArray1[i], inArray2[i], outArray[i])) - { - return false; - } - } - return true; - } - - public void Dispose() - { - inHandle1.Free(); - inHandle2.Free(); - outHandle.Free(); - } - } - - } -} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest.template index a8ea21cef8bb..a3d275190a29 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest.template +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest.template @@ -19,23 +19,41 @@ namespace JIT.HardwareIntrinsics.X86 {{ public static partial class Program {{ - private static void {1}{2}() + private static void {2}{3}() {{ - var test = new BooleanComparisonOpTest__{1}{2}(); + var test = new BooleanComparisonOpTest__{2}{3}(); if (test.IsSupported) {{ - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -56,73 +74,115 @@ namespace JIT.HardwareIntrinsics.X86 }} }} - public sealed unsafe class BooleanComparisonOpTest__{1}{2} + public sealed unsafe class BooleanComparisonOpTest__{2}{3} {{ - private const int VectorSize = {4}; - private const int ElementCount = VectorSize / sizeof({2}); + private const int VectorSize = {5}; + private const int ElementCount = VectorSize / sizeof({3}); - private static {2}[] _data1 = new {2}[ElementCount]; - private static {2}[] _data2 = new {2}[ElementCount]; + private static {3}[] _data1 = new {3}[ElementCount]; + private static {3}[] _data2 = new {3}[ElementCount]; - private static {3}<{2}> _clsVar1; - private static {3}<{2}> _clsVar2; + private static {4}<{3}> _clsVar1; + private static {4}<{3}> _clsVar2; - private {3}<{2}> _fld1; - private {3}<{2}> _fld2; + private {4}<{3}> _fld1; + private {4}<{3}> _fld2; - private BooleanComparisonOpTest__DataTable<{2}> _dataTable; + private BooleanComparisonOpTest__DataTable<{3}> _dataTable; - static BooleanComparisonOpTest__{1}{2}() + static BooleanComparisonOpTest__{2}{3}() {{ var random = new Random(); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar1), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar2), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar1), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar2), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize); }} - public BooleanComparisonOpTest__{1}{2}() + public BooleanComparisonOpTest__{2}{3}() {{ Succeeded = true; var random = new Random(); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld1), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld2), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld1), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld2), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - _dataTable = new BooleanComparisonOpTest__DataTable<{2}>(_data1, _data2); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + _dataTable = new BooleanComparisonOpTest__DataTable<{3}>(_data1, _data2, VectorSize); }} public bool IsSupported => {0}.IsSupported; public bool Succeeded {{ get; set; }} - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}( + Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_Load() {{ - var result = {0}.{1}( - Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr) + var result = {0}.{2}( + {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunBasicScenario_LoadAligned() + {{ + var result = {0}.{2}( + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) + .Invoke(null, new object[] {{ + Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); }} - public void RunReflectionScenario() + public void RunReflectionScenario_Load() {{ - var result = typeof({0}).GetMethod(nameof({0}.{1}), new Type[] {{ typeof({3}<{2}>), typeof({3}<{2}>) }}) + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) .Invoke(null, new object[] {{ - Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr) + {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)) }}); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)) + }}); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); }} public void RunClsVarScenario() {{ - var result = {0}.{1}( + var result = {0}.{2}( _clsVar1, _clsVar2 ); @@ -130,26 +190,44 @@ namespace JIT.HardwareIntrinsics.X86 ValidateResult(_clsVar1, _clsVar2, result); }} - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() + {{ + var left = Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_Load() {{ - var left = Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr); - var right = Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr); - var result = {0}.{1}(left, right); + var left = {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)); + var right = {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + ValidateResult(left, right, result); + }} + + public void RunLclVarScenario_LoadAligned() + {{ + var left = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)); + var right = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); ValidateResult(left, right, result); }} public void RunLclFldScenario() {{ - var test = new BooleanComparisonOpTest__{1}{2}(); - var result = {0}.{1}(test._fld1, test._fld2); + var test = new BooleanComparisonOpTest__{2}{3}(); + var result = {0}.{2}(test._fld1, test._fld2); ValidateResult(test._fld1, test._fld2, result); }} public void RunFldScenario() {{ - var result = {0}.{1}(_fld1, _fld2); + var result = {0}.{2}(_fld1, _fld2); ValidateResult(_fld1, _fld2, result); }} @@ -160,7 +238,7 @@ namespace JIT.HardwareIntrinsics.X86 try {{ - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); }} catch (PlatformNotSupportedException) {{ @@ -168,10 +246,10 @@ namespace JIT.HardwareIntrinsics.X86 }} }} - private void ValidateResult({3}<{2}> left, {3}<{2}> right, bool result, [CallerMemberName] string method = "") + private void ValidateResult({4}<{3}> left, {4}<{3}> right, bool result, [CallerMemberName] string method = "") {{ - {2}[] inArray1 = new {2}[ElementCount]; - {2}[] inArray2 = new {2}[ElementCount]; + {3}[] inArray1 = new {3}[ElementCount]; + {3}[] inArray2 = new {3}[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); @@ -179,13 +257,24 @@ namespace JIT.HardwareIntrinsics.X86 ValidateResult(inArray1, inArray2, result, method); }} - private void ValidateResult({2}[] left, {2}[] right, bool result, [CallerMemberName] string method = "") + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + {{ + {3}[] inArray1 = new {3}[ElementCount]; + {3}[] inArray2 = new {3}[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + }} + + private void ValidateResult({3}[] left, {3}[] right, bool result, [CallerMemberName] string method = "") {{ - if ({6}) + if ({7}) {{ Succeeded = false; - Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{1})}}<{2}>: {{method}} failed:"); + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{3}>: {{method}} failed:"); Console.WriteLine($" left: ({{string.Join(", ", left)}})"); Console.WriteLine($" right: ({{string.Join(", ", right)}})"); Console.WriteLine($" result: ({{string.Join(", ", result)}})"); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest_DataTable.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest_DataTable.cs index 56f07fb685fe..1315624e37c9 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest_DataTable.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/BooleanCmpOpTest_DataTable.cs @@ -12,28 +12,45 @@ namespace JIT.HardwareIntrinsics.X86 { public unsafe struct BooleanComparisonOpTest__DataTable : IDisposable where T : struct { + private byte[] inArray1; + private byte[] inArray2; + private GCHandle inHandle1; private GCHandle inHandle2; - public T[] inArray1; - public T[] inArray2; + private byte simdSize; - public BooleanComparisonOpTest__DataTable(T[] inArray1, T[] inArray2) + public BooleanComparisonOpTest__DataTable(T[] inArray1, T[] inArray2, int simdSize) { - this.inArray1 = inArray1; - this.inArray2 = inArray2; + this.inArray1 = new byte[simdSize * 2]; + this.inArray2 = new byte[simdSize * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); - this.inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned); - this.inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned); + this.simdSize = unchecked((byte)(simdSize)); + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), this.simdSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), this.simdSize); } - public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer(); - public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer(); + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), simdSize); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), simdSize); public void Dispose() { inHandle1.Free(); inHandle2.Free(); } + + private static unsafe void* Align(byte* buffer, byte expectedAlignment) + { + // Compute how bad the misalignment is, which is at most (expectedAlignment - 1). + // Then subtract that from the expectedAlignment and add it to the original address + // to compute the aligned address. + + var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment); + return (void*)(buffer + misalignment); + } } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index c5850cb1d484..5848273cc3dd 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -20,95 +20,95 @@ using System.IO; private static readonly (string templateFileName, string[] templateData)[] SseInputs = new [] { - // TemplateName Isa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Sse", "Add", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] + right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "AddScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "And", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "AndNot", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(~BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(~BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] == right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] == right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] == right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareGreaterThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] > right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareGreaterThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareGreaterThanOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] > right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareGreaterThanUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] > right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareGreaterThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] >= right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareGreaterThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareGreaterThanOrEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] >= right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareGreaterThanOrEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] >= right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareLessThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] < right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareLessThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareLessThanOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] < right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareLessThanUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] < right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareLessThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] <= right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareLessThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareLessThanOrEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] <= right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareLessThanOrEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] <= right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] != right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareNotEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] != right[0]) != result"}), - ("BooleanCmpOpTest.template", new string[] { "Sse", "CompareNotEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] != right[0]) != result"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotGreaterThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] > right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotGreaterThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotGreaterThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] >= right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotGreaterThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotLessThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] < right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotLessThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotLessThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] <= right[i]) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareNotLessThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareOrdered", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((!float.IsNaN(left[0]) && !float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((!float.IsNaN(left[i]) && !float.IsNaN(right[i])) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((!float.IsNaN(left[0]) && !float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareUnordered", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((float.IsNaN(left[0]) || float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((float.IsNaN(left[i]) || float.IsNaN(right[i])) ? -1 : 0)"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "CompareUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((float.IsNaN(left[0]) || float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Divide", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] / right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] / right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "DivideScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] / right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Max", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(Math.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "MaxScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Min", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(Math.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "MinScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Multiply", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "MultiplyScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Or", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) | BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) | BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Subtract", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] - right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] - right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "SubtractScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] - right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse", "Xor", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) ^ BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) ^ BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), + // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Add", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] + right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "AddScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "And", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "AndNot", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(~BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(~BitConverter.SingleToInt32Bits(left[0]) & BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] == right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] == right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] == right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] == right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] > right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] > right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] > right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] >= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanOrEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] >= right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareGreaterThanOrEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] >= right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareLessThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] < right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] < right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] < right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] <= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanOrEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] <= right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareLessThanOrEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] <= right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((left[i] != right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((left[0] != right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareNotEqualOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] != right[0]) != result"}), + ("BooleanCmpOpTest.template", new string[] { "Sse", "Sse", "CompareNotEqualUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(left[0] != right[0]) != result"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotGreaterThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] > right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotGreaterThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] > right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotGreaterThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] >= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotGreaterThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] >= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotLessThan", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] < right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotLessThanScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] < right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotLessThanOrEqual", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != (!(left[i] <= right[i]) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareNotLessThanOrEqualScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != (!(left[0] <= right[0]) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareOrdered", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((!float.IsNaN(left[0]) && !float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((!float.IsNaN(left[i]) && !float.IsNaN(right[i])) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareOrderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((!float.IsNaN(left[0]) && !float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareUnordered", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((float.IsNaN(left[0]) || float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(result[i]) != ((float.IsNaN(left[i]) || float.IsNaN(right[i])) ? -1 : 0)"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "CompareUnorderedScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(result[0]) != ((float.IsNaN(left[0]) || float.IsNaN(right[0])) ? -1 : 0)", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Divide", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] / right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] / right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "DivideScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] / right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Max", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(Math.Max(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "MaxScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Max(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Min", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(Math.Min(left[i], right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "MinScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(Math.Min(left[0], right[0])) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Multiply", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "MultiplyScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Or", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) | BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) | BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Subtract", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] - right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] - right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "SubtractScalar", "Single", "Vector128", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] - right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse", "Sse", "Xor", "Single", "Vector128", "16", "(float)(random.NextDouble())", "(BitConverter.SingleToInt32Bits(left[0]) ^ BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(left[0]) ^ BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])"}), }; private static readonly (string templateFileName, string[] templateData)[] Sse2Inputs = new [] { - // TemplateName Isa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Sse2", "Add", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), + // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Double", "Vector128", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Byte", "Vector128", "16", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int16", "Vector128", "16", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int32", "Vector128", "16", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "Int64", "Vector128", "16", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "SByte", "Vector128", "16", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt16", "Vector128", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt32", "Vector128", "16", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Sse2", "Sse2", "Add", "UInt64", "Vector128", "16", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), }; private static readonly (string templateFileName, string[] templateData)[] AvxInputs = new [] { - // TemplateName Isa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Avx", "Add", "Double", "Vector256", "32", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Avx", "Add", "Single", "Vector256", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] + right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Avx", "Multiply", "Double", "Vector256", "32", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), - ("SimpleBinOpTest.template", new string[] { "Avx", "Multiply", "Single", "Vector256", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Avx", "Avx", "Add", "Double", "Vector256", "32", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Avx", "Avx", "Add", "Single", "Vector256", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] + right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] + right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Avx", "Avx", "Multiply", "Double", "Vector256", "32", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new string[] { "Avx", "Avx", "Multiply", "Single", "Vector256", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), }; private static readonly (string templateFileName, string[] templateData)[] Avx2Inputs = new [] { - // TemplateName Isa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Byte", "Vector256", "32", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int16", "Vector256", "32", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int32", "Vector256", "32", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int64", "Vector256", "32", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "SByte", "Vector256", "32", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt16", "Vector256", "32", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt32", "Vector256", "32", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), - ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt64", "Vector256", "32", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), + // TemplateName Isa, LoadIsa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "Byte", "Vector256", "32", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "Int16", "Vector256", "32", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "Int32", "Vector256", "32", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "Int64", "Vector256", "32", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "SByte", "Vector256", "32", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "UInt16", "Vector256", "32", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "UInt32", "Vector256", "32", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Add", "UInt64", "Vector256", "32", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), }; private static void ProcessInputs(string isa, (string templateFileName, string[] templateData)[] inputs) @@ -146,10 +146,10 @@ namespace JIT.HardwareIntrinsics.X86 private static void ProcessInput(StreamWriter testListFile, (string templateFileName, string[] templateData) input) { - var testName = $"{input.templateData[1]}.{input.templateData[2]}"; + var testName = $"{input.templateData[2]}.{input.templateData[3]}"; // Ex: ["Add.Single"] = AddSingle - testListFile.WriteLine($@" [""{testName}""] = {input.templateData[1]}{input.templateData[2]},"); + testListFile.WriteLine($@" [""{testName}""] = {input.templateData[2]}{input.templateData[3]},"); var testFileName = Path.Combine("..", input.templateData[0], $"{testName}.cs"); var template = File.ReadAllText(input.templateFileName); @@ -163,6 +163,8 @@ private static void ProcessInput(StreamWriter testListFile, (string templateFile } ProcessInputs("Sse", SseInputs); -ProcessInputs("Sse2", Sse2Inputs); -ProcessInputs("Avx", AvxInputs); -ProcessInputs("Avx2", Avx2Inputs); + +// TODO-XArch: Re-enable after the Load and LoadAligned intrinsics are implemented for SSE2 and AVX +// ProcessInputs("Sse2", Sse2Inputs); +// ProcessInputs("Avx", AvxInputs); +// ProcessInputs("Avx2", Avx2Inputs); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template index 451cb9a19453..feff6f688ee2 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template @@ -19,23 +19,41 @@ namespace JIT.HardwareIntrinsics.X86 {{ public static partial class Program {{ - private static void {1}{2}() + private static void {2}{3}() {{ - var test = new SimpleBinaryOpTest__{1}{2}(); + var test = new SimpleBinaryOpTest__{2}{3}(); if (test.IsSupported) {{ - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -56,108 +74,174 @@ namespace JIT.HardwareIntrinsics.X86 }} }} - public sealed unsafe class SimpleBinaryOpTest__{1}{2} + public sealed unsafe class SimpleBinaryOpTest__{2}{3} {{ - private const int VectorSize = {4}; - private const int ElementCount = VectorSize / sizeof({2}); + private const int VectorSize = {5}; + private const int ElementCount = VectorSize / sizeof({3}); - private static {2}[] _data1 = new {2}[ElementCount]; - private static {2}[] _data2 = new {2}[ElementCount]; + private static {3}[] _data1 = new {3}[ElementCount]; + private static {3}[] _data2 = new {3}[ElementCount]; - private static {3}<{2}> _clsVar1; - private static {3}<{2}> _clsVar2; + private static {4}<{3}> _clsVar1; + private static {4}<{3}> _clsVar2; - private {3}<{2}> _fld1; - private {3}<{2}> _fld2; + private {4}<{3}> _fld1; + private {4}<{3}> _fld2; - private SimpleBinaryOpTest__DataTable<{2}> _dataTable; + private SimpleBinaryOpTest__DataTable<{3}> _dataTable; - static SimpleBinaryOpTest__{1}{2}() + static SimpleBinaryOpTest__{2}{3}() {{ var random = new Random(); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar1), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar2), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar1), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar2), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize); }} - public SimpleBinaryOpTest__{1}{2}() + public SimpleBinaryOpTest__{2}{3}() {{ Succeeded = true; var random = new Random(); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld1), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize); - Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld2), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld1), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld2), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize); - for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }} - _dataTable = new SimpleBinaryOpTest__DataTable<{2}>(_data1, _data2, new {2}[ElementCount]); + for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; }} + _dataTable = new SimpleBinaryOpTest__DataTable<{3}>(_data1, _data2, new {3}[ElementCount], VectorSize); }} public bool IsSupported => {0}.IsSupported; public bool Succeeded {{ get; set; }} - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}( + Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + }} + + public void RunBasicScenario_Load() {{ - var result = {0}.{1}( - Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr) + var result = {0}.{2}( + {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)) ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); }} - public void RunReflectionScenario() + public void RunBasicScenario_LoadAligned() {{ - var result = typeof({0}).GetMethod(nameof({0}.{1}), new Type[] {{ typeof({3}<{2}>), typeof({3}<{2}>) }}) + var result = {0}.{2}( + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) .Invoke(null, new object[] {{ - Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr), - Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr) + Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr) }}); - Unsafe.Write(_dataTable.outArrayPtr, ({3}<{2}>)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_Load() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) + .Invoke(null, new object[] {{ + {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)) + }}); + + Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)), + {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)) + }}); + + Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); }} public void RunClsVarScenario() {{ - var result = {0}.{1}( + var result = {0}.{2}( _clsVar1, _clsVar2 ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + }} + + public void RunLclVarScenario_UnsafeRead() + {{ + var left = Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr); + var result = {0}.{2}(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + }} + + public void RunLclVarScenario_Load() + {{ + var left = {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)); + var right = {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); }} - public void RunLclVarScenario() + public void RunLclVarScenario_LoadAligned() {{ - var left = Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr); - var right = Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr); - var result = {0}.{1}(left, right); + var left = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)); + var right = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)); + var result = {0}.{2}(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); }} public void RunLclFldScenario() {{ - var test = new SimpleBinaryOpTest__{1}{2}(); - var result = {0}.{1}(test._fld1, test._fld2); + var test = new SimpleBinaryOpTest__{2}{3}(); + var result = {0}.{2}(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); }} public void RunFldScenario() {{ - var result = {0}.{1}(_fld1, _fld2); + var result = {0}.{2}(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); }} public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ namespace JIT.HardwareIntrinsics.X86 try {{ - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); }} catch (PlatformNotSupportedException) {{ @@ -174,20 +258,35 @@ namespace JIT.HardwareIntrinsics.X86 }} }} - private void ValidateResult({3}<{2}> left, {3}<{2}> right, {2}[] result, [CallerMemberName] string method = "") + private void ValidateResult({4}<{3}> left, {4}<{3}> right, void* result, [CallerMemberName] string method = "") {{ - {2}[] inArray1 = new {2}[ElementCount]; - {2}[] inArray2 = new {2}[ElementCount]; + {3}[] inArray1 = new {3}[ElementCount]; + {3}[] inArray2 = new {3}[ElementCount]; + {3}[] outArray = new {3}[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + }} + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + {{ + {3}[] inArray1 = new {3}[ElementCount]; + {3}[] inArray2 = new {3}[ElementCount]; + {3}[] outArray = new {3}[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); }} - private void ValidateResult({2}[] left, {2}[] right, {2}[] result, [CallerMemberName] string method = "") + private void ValidateResult({3}[] left, {3}[] right, {3}[] result, [CallerMemberName] string method = "") {{ - if ({6}) + if ({7}) {{ Succeeded = false; }} @@ -195,7 +294,7 @@ namespace JIT.HardwareIntrinsics.X86 {{ for (var i = 1; i < left.Length; i++) {{ - if ({7}) + if ({8}) {{ Succeeded = false; break; @@ -205,7 +304,7 @@ namespace JIT.HardwareIntrinsics.X86 if (!Succeeded) {{ - Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{1})}}<{2}>: {{method}} failed:"); + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{3}>: {{method}} failed:"); Console.WriteLine($" left: ({{string.Join(", ", left)}})"); Console.WriteLine($" right: ({{string.Join(", ", right)}})"); Console.WriteLine($" result: ({{string.Join(", ", result)}})"); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable_Aligned.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable_Aligned.cs new file mode 100644 index 000000000000..f056a8fc7b93 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable_Aligned.cs @@ -0,0 +1,62 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public unsafe struct SimpleBinaryOpTest__DataTable : IDisposable where T : struct + { + private byte[] inArray1; + private byte[] inArray2; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle inHandle2; + private GCHandle outHandle; + + private byte simdSize; + + public SimpleBinaryOpTest__DataTable(T[] inArray1, T[] inArray2, T[] outArray, int simdSize) + { + this.inArray1 = new byte[simdSize * 2]; + this.inArray2 = new byte[simdSize * 2]; + this.outArray = new byte[simdSize * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.simdSize = unchecked((byte)(simdSize)); + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), this.simdSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray2Ptr), ref Unsafe.As(ref inArray2[0]), this.simdSize); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), simdSize); + public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), simdSize); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), simdSize); + + public void Dispose() + { + inHandle1.Free(); + inHandle2.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, byte expectedAlignment) + { + // Compute how bad the misalignment is, which is at most (expectedAlignment - 1). + // Then subtract that from the expectedAlignment and add it to the original address + // to compute the aligned address. + + var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment); + return (void*)(buffer + misalignment); + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Add.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Add.Single.cs index 030dc89b8cb1..c894d11fb10b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Add.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Add.Single.cs @@ -25,17 +25,35 @@ private static void AddSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__AddSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Add( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Add( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Add( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Add), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Add), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Add), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Add(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Add(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Add(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/AddScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/AddScalar.Single.cs index 325f7503b877..3e594225d613 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/AddScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/AddScalar.Single.cs @@ -25,17 +25,35 @@ private static void AddScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__AddScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.AddScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.AddScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.AddScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.AddScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.AddScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.AddScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.AddScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.AddScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.AddScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.AddScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.AddScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/And.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/And.Single.cs index 24f39682422f..984a441810df 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/And.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/And.Single.cs @@ -25,17 +25,35 @@ private static void AndSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__AndSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.And( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.And( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.And( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.And), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.And), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.And), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.And(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.And(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.And(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.And(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/AndNot.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/AndNot.Single.cs index 8ebf14948fa2..a5c8aba65516 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/AndNot.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/AndNot.Single.cs @@ -25,17 +25,35 @@ private static void AndNotSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__AndNotSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.AndNot( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.AndNot( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.AndNot( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.AndNot), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.AndNot), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.AndNot), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.AndNot(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.AndNot(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.AndNot(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.AndNot(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqual.Single.cs index a5b793457027..96da10ce4e26 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualOrderedScalar.Single.cs index 19e2e024d3e7..cf99b9694a27 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareEqualOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareEqualOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareEqualOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareEqualOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareEqualOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareEqualOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] == right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualScalar.Single.cs index 3a963b32673e..b6ecfb7c9a6c 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualUnorderedScalar.Single.cs index 4e95e71eb59c..6145e8869ccf 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareEqualUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareEqualUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareEqualUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareEqualUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareEqualUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareEqualUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareEqualUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] == right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThan.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThan.Single.cs index 54bc76d030bc..d351fd4f8e25 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThan.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThan.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareGreaterThanSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThan( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThan( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThan( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareGreaterThan(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareGreaterThan(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareGreaterThan(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqual.Single.cs index efe221858a8e..777796ff8917 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanOrEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareGreaterThanOrEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanOrEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanOrEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanOrEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareGreaterThanOrEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareGreaterThanOrEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareGreaterThanOrEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualOrderedScalar.Single.cs index 9c8b6e4d30dd..bf5c87d79d05 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanOrEqualOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareGreaterThanOrEqualOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanOrEqualOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanOrEqualOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanOrEqualOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareGreaterThanOrEqualOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] >= right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualScalar.Single.cs index 638bd2e7ce37..f6179e306567 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanOrEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareGreaterThanOrEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanOrEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanOrEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanOrEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareGreaterThanOrEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareGreaterThanOrEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareGreaterThanOrEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualUnorderedScalar.Single.cs index c1c4a7f707f3..536688be34ca 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrEqualUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanOrEqualUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareGreaterThanOrEqualUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanOrEqualUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanOrEqualUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanOrEqualUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareGreaterThanOrEqualUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] >= right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrderedScalar.Single.cs index 51dd48ca7474..1dec832ed190 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareGreaterThanOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareGreaterThanOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] > right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanScalar.Single.cs index 8598471ab6b4..38d4e2a80d4f 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareGreaterThanScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareGreaterThanScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareGreaterThanScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareGreaterThanScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanUnorderedScalar.Single.cs index 9a0d11e4491d..ffa170253f11 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareGreaterThanUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareGreaterThanUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareGreaterThanUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareGreaterThanUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareGreaterThanUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareGreaterThanUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareGreaterThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareGreaterThanUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareGreaterThanUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] > right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThan.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThan.Single.cs index 5a13fe2d6d2e..d5ee27689c79 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThan.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThan.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareLessThanSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThan( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThan( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThan( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareLessThan(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareLessThan(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareLessThan(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqual.Single.cs index 11683c99723e..a38d9c5217ed 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanOrEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareLessThanOrEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanOrEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanOrEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanOrEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareLessThanOrEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareLessThanOrEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareLessThanOrEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualOrderedScalar.Single.cs index bb22aa7c5fa5..99a6fcf9bcf1 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanOrEqualOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareLessThanOrEqualOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanOrEqualOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanOrEqualOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanOrEqualOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareLessThanOrEqualOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] <= right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualScalar.Single.cs index 89e451ddf0e7..7fd66419970d 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanOrEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareLessThanOrEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanOrEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanOrEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanOrEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareLessThanOrEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareLessThanOrEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareLessThanOrEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualUnorderedScalar.Single.cs index 35d6708b6363..9ee802373808 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrEqualUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanOrEqualUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareLessThanOrEqualUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanOrEqualUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanOrEqualUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanOrEqualUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareLessThanOrEqualUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] <= right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrderedScalar.Single.cs index 9abafd999b9a..98a4a7884544 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareLessThanOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareLessThanOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] < right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanScalar.Single.cs index 2a347dd93483..448d1d6ba2af 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareLessThanScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareLessThanScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareLessThanScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareLessThanScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanUnorderedScalar.Single.cs index a1d5fefafecd..896d1d7fab27 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareLessThanUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareLessThanUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareLessThanUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareLessThanUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareLessThanUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareLessThanUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareLessThanUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareLessThanUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareLessThanUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] < right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqual.Single.cs index b39660afe1fe..f2e83025d707 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualOrderedScalar.Single.cs index 4e0f2adf40f8..75de4bfd4455 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotEqualOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareNotEqualOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotEqualOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotEqualOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotEqualOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualOrderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareNotEqualOrderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] != right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualScalar.Single.cs index cd0942efe9c6..78b4d4b87b2a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualUnorderedScalar.Single.cs index 36b04b4c8800..fc6cca61b38e 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotEqualUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotEqualUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,24 +110,44 @@ public BooleanComparisonOpTest__CompareNotEqualUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2); + _dataTable = new BooleanComparisonOpTest__DataTable(_data1, _data2, VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotEqualUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), Unsafe.Read>(_dataTable.inArray2Ptr) ); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotEqualUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotEqualUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, result); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -117,7 +155,29 @@ public void RunReflectionScenario() Unsafe.Read>(_dataTable.inArray2Ptr) }); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, (bool)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotEqualUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, (bool)(result)); } public void RunClsVarScenario() @@ -130,7 +190,7 @@ public void RunClsVarScenario() ValidateResult(_clsVar1, _clsVar2, result); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); @@ -139,6 +199,24 @@ public void RunLclVarScenario() ValidateResult(left, right, result); } + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotEqualUnorderedScalar(left, right); + + ValidateResult(left, right, result); + } + public void RunLclFldScenario() { var test = new BooleanComparisonOpTest__CompareNotEqualUnorderedScalarSingle(); @@ -160,7 +238,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -179,6 +257,17 @@ private void ValidateResult(Vector128 left, Vector128 right, boo ValidateResult(inArray1, inArray2, result, method); } + private void ValidateResult(void* left, void* right, bool result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + + ValidateResult(inArray1, inArray2, result, method); + } + private void ValidateResult(Single[] left, Single[] right, bool result, [CallerMemberName] string method = "") { if ((left[0] != right[0]) != result) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThan.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThan.Single.cs index 6d9bd2e08653..c2c3797d71dd 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThan.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThan.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotGreaterThanSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotGreaterThanSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotGreaterThan( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotGreaterThan( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotGreaterThan( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotGreaterThan(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotGreaterThan(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotGreaterThan(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqual.Single.cs index 29891c962173..c23755d60765 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotGreaterThanOrEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotGreaterThanOrEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotGreaterThanOrEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotGreaterThanOrEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotGreaterThanOrEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotGreaterThanOrEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotGreaterThanOrEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotGreaterThanOrEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqualScalar.Single.cs index 33a3687862a7..dca83ff9455e 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanOrEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotGreaterThanOrEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotGreaterThanOrEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotGreaterThanOrEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotGreaterThanOrEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotGreaterThanOrEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotGreaterThanOrEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotGreaterThanOrEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotGreaterThanOrEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanScalar.Single.cs index f3d06f048db4..61b365e0b68f 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotGreaterThanScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotGreaterThanScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotGreaterThanScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotGreaterThanScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotGreaterThanScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotGreaterThanScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotGreaterThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotGreaterThanScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotGreaterThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotGreaterThanScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotGreaterThanScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThan.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThan.Single.cs index af354e4fe73a..20d6b0190121 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThan.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThan.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotLessThanSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotLessThanSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotLessThan( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotLessThan( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotLessThan( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThan), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotLessThan(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThan(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotLessThan(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotLessThan(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqual.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqual.Single.cs index cfe4d4d5d46e..939bfa9b5189 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqual.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqual.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotLessThanOrEqualSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotLessThanOrEqualSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotLessThanOrEqual( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotLessThanOrEqual( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotLessThanOrEqual( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqual), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotLessThanOrEqual(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanOrEqual(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotLessThanOrEqual(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotLessThanOrEqual(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqualScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqualScalar.Single.cs index b96ea1573a03..f8edf87bb781 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqualScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanOrEqualScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotLessThanOrEqualScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotLessThanOrEqualScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotLessThanOrEqualScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotLessThanOrEqualScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotLessThanOrEqualScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanOrEqualScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotLessThanOrEqualScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanOrEqualScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotLessThanOrEqualScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotLessThanOrEqualScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanScalar.Single.cs index f308dab02136..02fc9885cfe9 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareNotLessThanScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareNotLessThanScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareNotLessThanScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareNotLessThanScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareNotLessThanScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareNotLessThanScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareNotLessThanScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareNotLessThanScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareNotLessThanScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareNotLessThanScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareNotLessThanScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrdered.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrdered.Single.cs index 82cd8757740d..cf7b8977465c 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrdered.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrdered.Single.cs @@ -25,17 +25,35 @@ private static void CompareOrderedSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareOrderedSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareOrdered( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareOrdered( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareOrdered( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrdered), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareOrdered(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareOrdered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareOrdered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareOrdered(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareOrdered(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrderedScalar.Single.cs index 42e018946a29..8e64be1bf556 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareOrderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareOrderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareOrderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareOrderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareOrderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareOrderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareOrderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareOrderedScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareOrderedScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareOrderedScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareOrderedScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareOrderedScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnordered.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnordered.Single.cs index 434812197288..70c0a8c80c75 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnordered.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnordered.Single.cs @@ -25,17 +25,35 @@ private static void CompareUnorderedSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareUnorderedSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareUnordered( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareUnordered( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareUnordered( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnordered), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnordered), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnordered), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareUnordered(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareUnordered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareUnordered(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareUnordered(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareUnordered(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnorderedScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnorderedScalar.Single.cs index 08d3c91dd6ec..7466b711c16b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnorderedScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/CompareUnorderedScalar.Single.cs @@ -25,17 +25,35 @@ private static void CompareUnorderedScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__CompareUnorderedScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.CompareUnorderedScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.CompareUnorderedScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.CompareUnorderedScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.CompareUnorderedScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.CompareUnorderedScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareUnorderedScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.CompareUnorderedScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.CompareUnorderedScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.CompareUnorderedScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Divide.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Divide.Single.cs index 1e756361c803..ca5d35cc63c7 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Divide.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Divide.Single.cs @@ -25,17 +25,35 @@ private static void DivideSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__DivideSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Divide( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Divide( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Divide( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Divide), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Divide), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Divide), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Divide(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Divide(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Divide(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Divide(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Divide(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/DivideScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/DivideScalar.Single.cs index 1f366ddb7b8d..001b209d78c7 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/DivideScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/DivideScalar.Single.cs @@ -25,17 +25,35 @@ private static void DivideScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__DivideScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.DivideScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.DivideScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.DivideScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.DivideScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.DivideScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.DivideScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.DivideScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.DivideScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.DivideScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.DivideScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.DivideScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Max.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Max.Single.cs index 5aa37e75274c..d8b364165300 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Max.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Max.Single.cs @@ -25,17 +25,35 @@ private static void MaxSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MaxSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Max( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Max( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Max( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Max), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Max(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Max(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Max(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Max(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MaxScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MaxScalar.Single.cs index 4edbc9c08831..40198d0e636a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MaxScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MaxScalar.Single.cs @@ -25,17 +25,35 @@ private static void MaxScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MaxScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.MaxScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.MaxScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.MaxScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.MaxScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MaxScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MaxScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.MaxScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MaxScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MaxScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.MaxScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.MaxScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Min.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Min.Single.cs index 8a4d6269a9bf..75413737b04a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Min.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Min.Single.cs @@ -25,17 +25,35 @@ private static void MinSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MinSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Min( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Min( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Min( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Min), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Min(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Min(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Min(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Min(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MinScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MinScalar.Single.cs index 4f07b11f8efa..9efe272ab598 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MinScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MinScalar.Single.cs @@ -25,17 +25,35 @@ private static void MinScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MinScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.MinScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.MinScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.MinScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.MinScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MinScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MinScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.MinScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MinScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MinScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.MinScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.MinScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Multiply.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Multiply.Single.cs index 9419c0f89887..ba603f8ddd99 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Multiply.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Multiply.Single.cs @@ -25,17 +25,35 @@ private static void MultiplySingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MultiplySingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Multiply( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Multiply( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Multiply( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Multiply), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Multiply), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Multiply), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Multiply(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Multiply(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Multiply(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Multiply(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MultiplyScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MultiplyScalar.Single.cs index 765a464437dc..cc353e45a0fb 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/MultiplyScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/MultiplyScalar.Single.cs @@ -25,17 +25,35 @@ private static void MultiplyScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__MultiplyScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.MultiplyScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.MultiplyScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.MultiplyScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.MultiplyScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.MultiplyScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MultiplyScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.MultiplyScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.MultiplyScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.MultiplyScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Or.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Or.Single.cs index f70a5ed717ad..93b8539fdfed 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Or.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Or.Single.cs @@ -25,17 +25,35 @@ private static void OrSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__OrSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Or( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Or( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Or( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Or), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Or), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Or), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Or(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Or(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Or(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Or(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_r.csproj index ee3966d9b2a8..2b0e208ecc74 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_r.csproj @@ -82,7 +82,7 @@ - + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_ro.csproj index 946557677a63..15e880b7eb7b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Sse_ro.csproj @@ -82,7 +82,7 @@ - + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Subtract.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Subtract.Single.cs index c6e0f1c7e195..7a2bda1e6a2d 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Subtract.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Subtract.Single.cs @@ -25,17 +25,35 @@ private static void SubtractSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__SubtractSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Subtract( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Subtract( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Subtract( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Subtract), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Subtract), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Subtract), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Subtract(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Subtract(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Subtract(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Subtract(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/SubtractScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/SubtractScalar.Single.cs index 6f706771ff45..e6a475e7a088 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/SubtractScalar.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/SubtractScalar.Single.cs @@ -25,17 +25,35 @@ private static void SubtractScalarSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__SubtractScalarSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.SubtractScalar( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.SubtractScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.SubtractScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.SubtractScalar), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.SubtractScalar(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.SubtractScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.SubtractScalar(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.SubtractScalar(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.SubtractScalar(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Xor.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Xor.Single.cs index 13a5e34be1f8..6af8bc33c234 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse/Xor.Single.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse/Xor.Single.cs @@ -25,17 +25,35 @@ private static void XorSingle() if (test.IsSupported) { - // Validates basic functionality works - test.RunBasicScenario(); + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); - // Validates calling via reflection works - test.RunReflectionScenario(); + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); // Validates passing a static member works test.RunClsVarScenario(); - // Validates passing a local works - test.RunLclVarScenario(); + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); // Validates passing the field of a local works test.RunLclFldScenario(); @@ -92,14 +110,14 @@ public SimpleBinaryOpTest__XorSingle() Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); for (var i = 0; i < ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); _data2[i] = (float)(random.NextDouble()); } - _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount]); + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Single[ElementCount], VectorSize); } public bool IsSupported => Sse.IsSupported; public bool Succeeded { get; set; } - public void RunBasicScenario() + public void RunBasicScenario_UnsafeRead() { var result = Sse.Xor( Unsafe.Read>(_dataTable.inArray1Ptr), @@ -107,10 +125,32 @@ public void RunBasicScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Sse.Xor( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Sse.Xor( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } - public void RunReflectionScenario() + public void RunReflectionScenario_UnsafeRead() { var result = typeof(Sse).GetMethod(nameof(Sse.Xor), new Type[] { typeof(Vector128), typeof(Vector128) }) .Invoke(null, new object[] { @@ -119,7 +159,31 @@ public void RunReflectionScenario() }); Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); - ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Xor), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Sse).GetMethod(nameof(Sse.Xor), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)), + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); } public void RunClsVarScenario() @@ -130,17 +194,37 @@ public void RunClsVarScenario() ); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); } - public void RunLclVarScenario() + public void RunLclVarScenario_UnsafeRead() { var left = Unsafe.Read>(_dataTable.inArray1Ptr); var right = Unsafe.Read>(_dataTable.inArray2Ptr); var result = Sse.Xor(left, right); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(left, right, _dataTable.outArray); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var right = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray2Ptr)); + var result = Sse.Xor(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); } public void RunLclFldScenario() @@ -149,7 +233,7 @@ public void RunLclFldScenario() var result = Sse.Xor(test._fld1, test._fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); } public void RunFldScenario() @@ -157,7 +241,7 @@ public void RunFldScenario() var result = Sse.Xor(_fld1, _fld2); Unsafe.Write(_dataTable.outArrayPtr, result); - ValidateResult(_fld1, _fld2, _dataTable.outArray); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); } public void RunUnsupportedScenario() @@ -166,7 +250,7 @@ public void RunUnsupportedScenario() try { - RunBasicScenario(); + RunBasicScenario_UnsafeRead(); } catch (PlatformNotSupportedException) { @@ -174,15 +258,30 @@ public void RunUnsupportedScenario() } } - private void ValidateResult(Vector128 left, Vector128 right, Single[] result, [CallerMemberName] string method = "") + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") { Single[] inArray1 = new Single[ElementCount]; Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[ElementCount]; + Single[] inArray2 = new Single[ElementCount]; + Single[] outArray = new Single[ElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), VectorSize); - ValidateResult(inArray1, inArray2, result, method); + ValidateResult(inArray1, inArray2, outArray, method); } private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "")