diff options
author | Juan Carlos Aguilera Mendez <juanam@microsoft.com> | 2018-03-14 16:34:00 -0700 |
---|---|---|
committer | Juan Carlos Aguilera Mendez <juanam@microsoft.com> | 2018-03-14 16:34:00 -0700 |
commit | 4fa5ee3a3de97a9f144677a6ea0a69e0bac7bf3e (patch) | |
tree | 2eaab1297fb663a21b7a81fc973626e3ff5b50bb | |
parent | 3ea84968be81176a3aade78a799a540ed0b6aa49 (diff) | |
parent | 659267af49f89c0cae4dc5b49abee4cf6550c723 (diff) | |
download | coreclr-4fa5ee3a3de97a9f144677a6ea0a69e0bac7bf3e.tar.gz coreclr-4fa5ee3a3de97a9f144677a6ea0a69e0bac7bf3e.tar.bz2 coreclr-4fa5ee3a3de97a9f144677a6ea0a69e0bac7bf3e.zip |
Merge branch 'master' of https://github.com/dotnet/coreclr
58 files changed, 4141 insertions, 225 deletions
diff --git a/ILAsmVersion.txt b/ILAsmVersion.txt index b158773573..fbf7439af7 100644 --- a/ILAsmVersion.txt +++ b/ILAsmVersion.txt @@ -1 +1 @@ -2.1.0-preview2-26310-01 +2.1.0-preview2-26314-04 diff --git a/buildpipeline/perf-pipeline.groovy b/buildpipeline/perf-pipeline.groovy index 270c80eda3..f2043dc742 100644 --- a/buildpipeline/perf-pipeline.groovy +++ b/buildpipeline/perf-pipeline.groovy @@ -121,7 +121,6 @@ def windowsThroughput(String arch, String os, String config, String runType, Str bat "py \".\\Microsoft.BenchView.JSONFormat\\tools\\machinedata.py\"" bat ".\\init-tools.cmd" - bat "tests\\runtest.cmd ${config} ${arch} GenerateLayoutOnly" bat "py -u tests\\scripts\\run-throughput-perf.py -arch ${arch} -os ${os} -configuration ${config} -opt_level ${optLevel} -jit_name ${jit} ${pgoTestFlag} -clr_root \"%WORKSPACE%\" -assembly_root \"%WORKSPACE%\\${arch}ThroughputBenchmarks\\lib\" -benchview_path \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" -run_type ${runType}" archiveArtifacts allowEmptyArchive: false, artifacts:'throughput-*.csv,machinedata.json', onlyIfSuccessful: false } diff --git a/buildpipeline/pipelines.json b/buildpipeline/pipelines.json index 0b4edd06b9..e48305dcd4 100644 --- a/buildpipeline/pipelines.json +++ b/buildpipeline/pipelines.json @@ -141,21 +141,6 @@ "Architecture": "arm", "PB_BuildType": null } - }, - { - "Name": "DotNet-CoreClr-Trusted-Linux-Crossbuild", - "Parameters": { - "DockerTag": "ubuntu-16.04-cross-arm64-d809634-20180312171656", - "Architecture": "arm64", - "Rid": "linux" - }, - "ReportingParameters": { - "OperatingSystem": "Linux", - "SubType": "PortableCrossBuild", - "Type": "build/product/", - "Architecture": "arm64", - "PB_BuildType": null - } } ] } diff --git a/dependencies.props b/dependencies.props index bf557cdcac..c56c705f2a 100644 --- a/dependencies.props +++ b/dependencies.props @@ -23,18 +23,18 @@ <!-- Source of truth for dependency tooling: the commit hash of the dotnet/versions master branch as of the last auto-upgrade. --> <PropertyGroup> - <CoreFxCurrentRef>0e6f6fa6b335fa1e0c26c6f24031003cb2d48b81</CoreFxCurrentRef> - <CoreClrCurrentRef>51eda5ba26ef0ef0abee607a1fae2cf528110fc9</CoreClrCurrentRef> + <CoreFxCurrentRef>75e9cc395001be59566eb6d93eaa81d2b1ab9f61</CoreFxCurrentRef> + <CoreClrCurrentRef>b76c3bd6ccb431600df9361b396d1df5465dd061</CoreClrCurrentRef> <BuildToolsCurrentRef>0e6f6fa6b335fa1e0c26c6f24031003cb2d48b81</BuildToolsCurrentRef> <PgoDataCurrentRef>553f30357d08df4ed6d32f70f3478a76f5db79c2</PgoDataCurrentRef> </PropertyGroup> <!-- Tests/infrastructure dependency versions. --> <PropertyGroup> - <MicrosoftPrivateCoreFxNETCoreAppPackageVersion>4.5.0-preview2-26313-01</MicrosoftPrivateCoreFxNETCoreAppPackageVersion> - <MicrosoftNETCorePlatformsPackageVersion>2.1.0-preview2-26313-01</MicrosoftNETCorePlatformsPackageVersion> + <MicrosoftPrivateCoreFxNETCoreAppPackageVersion>4.5.0-preview2-26313-03</MicrosoftPrivateCoreFxNETCoreAppPackageVersion> + <MicrosoftNETCorePlatformsPackageVersion>2.1.0-preview2-26313-03</MicrosoftNETCorePlatformsPackageVersion> <PgoDataPackageVersion>99.99.99-master-20180228-0037</PgoDataPackageVersion> - <MicrosoftNETCoreRuntimeCoreCLRPackageVersion>2.1.0-preview2-26310-01</MicrosoftNETCoreRuntimeCoreCLRPackageVersion> + <MicrosoftNETCoreRuntimeCoreCLRPackageVersion>2.1.0-preview2-26314-04</MicrosoftNETCoreRuntimeCoreCLRPackageVersion> <XunitPackageVersion>2.2.0-beta2-build3300</XunitPackageVersion> <XunitConsoleNetcorePackageVersion>1.0.2-prerelease-00177</XunitConsoleNetcorePackageVersion> <XunitPerformanceApiPackageVersion>1.0.0-beta-build0015</XunitPerformanceApiPackageVersion> diff --git a/netci.groovy b/netci.groovy index 3a4ed5aef9..6b45ff7014 100755 --- a/netci.groovy +++ b/netci.groovy @@ -641,7 +641,7 @@ def static setJobTimeout(newJob, isPR, architecture, configuration, scenario, is timeout = 360 } else if (isJitStressScenario(scenario)) { - timeout = 240 + timeout = 300 } else if (isR2RBaselineScenario(scenario)) { timeout = 240 diff --git a/perf.groovy b/perf.groovy index b8366225bf..10903c2b58 100644 --- a/perf.groovy +++ b/perf.groovy @@ -200,7 +200,6 @@ def static getOSGroup(def os) { "py \"%WORKSPACE%\\Microsoft.BenchView.JSONFormat\\tools\\build.py\" git --branch %GIT_BRANCH_WITHOUT_ORIGIN% --type ${runType}") batchFile("py \"%WORKSPACE%\\Microsoft.BenchView.JSONFormat\\tools\\machinedata.py\"") batchFile("set __TestIntermediateDir=int&&build.cmd ${configuration} ${architecture}${pgo_build} skiptests") - batchFile("tests\\runtest.cmd ${configuration} ${architecture} GenerateLayoutOnly") batchFile("py -u tests\\scripts\\run-throughput-perf.py -arch ${arch} -os ${os} -configuration ${configuration} -opt_level ${opt_level} -jit_name ${jit}${pgo_test} -clr_root \"%WORKSPACE%\" -assembly_root \"%WORKSPACE%\\Microsoft.BenchView.ThroughputBenchmarks.${architecture}.${os}\\lib\" -benchview_path \"%WORKSPACE%\\Microsoft.Benchview.JSONFormat\\tools\" -run_type ${runType}") } } @@ -717,7 +716,7 @@ parallel( Utilities.standardJobSetup(newJob, project, false, "*/${branch}") // Set the cron job here. We run nightly on each flavor, regardless of code changes - //Utilities.addPeriodicTrigger(newJob, "@daily", true /*always run*/) + Utilities.addPeriodicTrigger(newJob, "@daily", true /*always run*/) newJob.with { logRotator { diff --git a/src/debug/daccess/nidump.cpp b/src/debug/daccess/nidump.cpp index 45320dca7f..e948687c0e 100644 --- a/src/debug/daccess/nidump.cpp +++ b/src/debug/daccess/nidump.cpp @@ -720,7 +720,7 @@ NativeImageDumper::DumpNativeImage() for (COUNT_T i = 0; i < m_decoder.GetNumberOfSections(); i++) { - PTR_IMAGE_SECTION_HEADER section = dptr_add(m_decoder.FindFirstSection(), i); + PTR_IMAGE_SECTION_HEADER section = m_decoder.FindFirstSection() + i; m_display->Section(reinterpret_cast<char *>(section->Name), section->VirtualAddress, section->SizeOfRawData); diff --git a/src/gc/gc.cpp b/src/gc/gc.cpp index 3bc2809564..a23edb9dff 100644 --- a/src/gc/gc.cpp +++ b/src/gc/gc.cpp @@ -1820,7 +1820,7 @@ retry: #ifdef SYNCHRONIZATION_STATS (spin_lock->num_switch_thread)++; #endif //SYNCHRONIZATION_STATS - BOOL cooperative_mode = gc_heap::enable_preemptive (); + bool cooperative_mode = gc_heap::enable_preemptive (); GCToOSInterface::YieldThread(0); @@ -26889,7 +26889,7 @@ void gc_heap::bgc_thread_function() BOOL do_exit = FALSE; - BOOL cooperative_mode = TRUE; + bool cooperative_mode = true; bgc_thread_id.SetToCurrentThread(); dprintf (1, ("bgc_thread_id is set to %x", (uint32_t)GCToOSInterface::GetCurrentThreadIdForLogging())); while (1) diff --git a/src/inc/pedecoder.h b/src/inc/pedecoder.h index 01375e6d88..8163ffff35 100644 --- a/src/inc/pedecoder.h +++ b/src/inc/pedecoder.h @@ -182,7 +182,7 @@ class PEDecoder UINT32 GetWin32VersionValue() const; COUNT_T GetNumberOfRvaAndSizes() const; COUNT_T GetNumberOfSections() const; - IMAGE_SECTION_HEADER *FindFirstSection() const; + PTR_IMAGE_SECTION_HEADER FindFirstSection() const; IMAGE_SECTION_HEADER *FindSection(LPCSTR sectionName) const; DWORD GetImageIdentity() const; diff --git a/src/inc/pedecoder.inl b/src/inc/pedecoder.inl index 7f3c79ba59..c8400af46a 100644 --- a/src/inc/pedecoder.inl +++ b/src/inc/pedecoder.inl @@ -1178,7 +1178,7 @@ inline DWORD PEDecoder::GetImageIdentity() const } -inline IMAGE_SECTION_HEADER *PEDecoder::FindFirstSection() const +inline PTR_IMAGE_SECTION_HEADER PEDecoder::FindFirstSection() const { CONTRACT(IMAGE_SECTION_HEADER *) { diff --git a/src/jit/emitxarch.cpp b/src/jit/emitxarch.cpp index 3f0b23dd79..4e1bec97fb 100644 --- a/src/jit/emitxarch.cpp +++ b/src/jit/emitxarch.cpp @@ -312,11 +312,12 @@ bool emitter::Is4ByteSSE4OrAVXInstruction(instruction ins) bool emitter::TakesVexPrefix(instruction ins) { // special case vzeroupper as it requires 2-byte VEX prefix - // special case the fencing and the prefetch instructions as they never take a VEX prefix + // special case the fencing, movnti and the prefetch instructions as they never take a VEX prefix switch (ins) { case INS_lfence: case INS_mfence: + case INS_movnti: case INS_prefetchnta: case INS_prefetcht0: case INS_prefetcht1: @@ -418,13 +419,21 @@ bool TakesRexWPrefix(instruction ins, emitAttr attr) if (IsSSEOrAVXInstruction(ins)) { - if (ins == INS_cvttsd2si || ins == INS_cvttss2si || ins == INS_cvtsd2si || ins == INS_cvtss2si || - ins == INS_cvtsi2sd || ins == INS_cvtsi2ss || ins == INS_mov_xmm2i || ins == INS_mov_i2xmm) + switch (ins) { - return true; + case INS_cvttsd2si: + case INS_cvttss2si: + case INS_cvtsd2si: + case INS_cvtss2si: + case INS_cvtsi2sd: + case INS_cvtsi2ss: + case INS_mov_xmm2i: + case INS_mov_i2xmm: + case INS_movnti: + return true; + default: + return false; } - - return false; } // TODO-XArch-Cleanup: Better way to not emit REX.W when we don't need it, than just testing all these diff --git a/src/jit/hwintrinsiccodegenxarch.cpp b/src/jit/hwintrinsiccodegenxarch.cpp index 77ba37c633..873f1c6dec 100644 --- a/src/jit/hwintrinsiccodegenxarch.cpp +++ b/src/jit/hwintrinsiccodegenxarch.cpp @@ -985,8 +985,6 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) assert(op1 != nullptr); assert(op2 == nullptr); instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType); - // TODO-XArch-CQ -> use of type size of TYP_SIMD16 leads to - // instruction register encoding errors for SSE legacy encoding emit->emitIns_R_R(ins, emitTypeSize(baseType), targetReg, op1Reg); break; } @@ -1084,6 +1082,18 @@ void CodeGen::genSSE2Intrinsic(GenTreeHWIntrinsic* node) break; } + case NI_SSE2_StoreNonTemporal: + { + assert(baseType == TYP_INT || baseType == TYP_UINT || baseType == TYP_LONG || baseType == TYP_ULONG); + assert(op1 != nullptr); + assert(op2 != nullptr); + + op2Reg = op2->gtRegNum; + instruction ins = Compiler::insOfHWIntrinsic(intrinsicID, baseType); + emit->emitIns_AR_R(ins, emitTypeSize(baseType), op2Reg, op1Reg, 0); + break; + } + default: unreached(); break; diff --git a/src/jit/hwintrinsiclistxarch.h b/src/jit/hwintrinsiclistxarch.h index c89995226b..c8c611f56d 100644 --- a/src/jit/hwintrinsiclistxarch.h +++ b/src/jit/hwintrinsiclistxarch.h @@ -100,7 +100,6 @@ HARDWARE_INTRINSIC(SSE_Reciprocal, "Reciprocal HARDWARE_INTRINSIC(SSE_ReciprocalScalar, "ReciprocalScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE_ReciprocalSqrt, "ReciprocalSqrt", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_ReciprocalSqrtScalar, "ReciprocalSqrtScalar", SSE, -1, 16, -1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) -HARDWARE_INTRINSIC(SSE_SetAllVector128, "SetAllVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Helper, HW_Flag_NoCodeGen|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_SetScalarVector128, "SetScalarVector128", SSE, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movss, INS_invalid}, HW_Category_Helper, HW_Flag_MultiIns|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_SetZeroVector128, "SetZeroVector128", SSE, -1, 16, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_xorps, INS_invalid}, HW_Category_Helper, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE_Shuffle, "Shuffle", SSE, -1, 16, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM) @@ -184,7 +183,7 @@ HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Int64, "ConvertSca HARDWARE_INTRINSIC(SSE2_ConvertToVector128Single, "ConvertToVector128Single", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtdq2ps, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtpd2ps}, HW_Category_SimpleSIMD, HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128Single, "ConvertScalarToVector128Single", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_cvtsd2ss, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_SpecialCodeGen) HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt32, "ConvertScalarToVector128UInt32", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_64BitOnly|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_ConvertScalarToVector128UInt64, "ConvertScalarToVector128UInt64", SSE2, -1, 16, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mov_i2xmm, INS_invalid, INS_invalid}, HW_Category_SIMDScalar, HW_Flag_64BitOnly|HW_Flag_SpecialCodeGen|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_Divide, "Divide", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_DivideScalar, "DivideScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_divsd}, HW_Category_SIMDScalar, HW_Flag_CopyUpperBits) HARDWARE_INTRINSIC(SSE2_Extract, "Extract", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_pextrw, INS_pextrw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_BaseTypeFromFirstArg|HW_Flag_NoRMWSemantics) @@ -229,6 +228,7 @@ HARDWARE_INTRINSIC(SSE2_StoreAligned, "StoreAlign HARDWARE_INTRINSIC(SSE2_StoreAlignedNonTemporal, "StoreAlignedNonTemporal", SSE2, -1, 16, 2, {INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_movntdq, INS_invalid, INS_movntpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_StoreHigh, "StoreHigh", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movhpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_StoreLow, "StoreLow", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movq, INS_movq, INS_invalid, INS_movlpd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(SSE2_StoreNonTemporal, "StoreNonTemporal", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movnti, INS_movnti, INS_movnti, INS_movnti, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoRMWSemantics|HW_Flag_SecondArgMaybe64Bit) HARDWARE_INTRINSIC(SSE2_StoreScalar, "StoreScalar", SSE2, -1, 16, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_movsdsse2}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(SSE2_Subtract, "Subtract", SSE2, -1, 16, 2, {INS_psubb, INS_psubb, INS_psubw, INS_psubw, INS_psubd, INS_psubd, INS_psubq, INS_psubq, INS_invalid, INS_subpd}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) HARDWARE_INTRINSIC(SSE2_SubtractSaturate, "SubtractSaturate", SSE2, -1, 16, 2, {INS_psubsb, INS_psubusb, INS_psubsw, INS_psubusw, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoFlag) @@ -359,6 +359,7 @@ HARDWARE_INTRINSIC(AVX_Max, "Max", HARDWARE_INTRINSIC(AVX_Min, "Min", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_minps, INS_minpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX_Multiply, "Multiply", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_mulps, INS_mulpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) HARDWARE_INTRINSIC(AVX_Or, "Or", AVX, -1, 32, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_orps, INS_orpd}, HW_Category_SimpleSIMD, HW_Flag_Commutative) +HARDWARE_INTRINSIC(AVX_Permute, "Permute", AVX, -1, 0, 2, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_vpermilps, INS_vpermilpd}, HW_Category_IMM, HW_Flag_FullRangeIMM|HW_Flag_UnfixedSIMDSize) HARDWARE_INTRINSIC(AVX_Reciprocal, "Reciprocal", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rcpps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_ReciprocalSqrt, "ReciprocalSqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_rsqrtps, INS_invalid}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_RoundCurrentDirection, "RoundCurrentDirection", AVX, 4, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) @@ -367,6 +368,7 @@ HARDWARE_INTRINSIC(AVX_RoundToNegativeInfinity, "RoundToNeg HARDWARE_INTRINSIC(AVX_RoundToPositiveInfinity, "RoundToPositiveInfinity", AVX, 10, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_RoundToZero, "RoundToZero", AVX, 11, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_roundps, INS_roundpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_SetZeroVector256, "SetZeroVector256", AVX, -1, 32, 0, {INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_pxor, INS_xorps, INS_xorpd}, HW_Category_Helper, HW_Flag_OneTypeGeneric|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(AVX_Shuffle, "Shuffle", AVX, -1, 32, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_shufps, INS_shufpd}, HW_Category_IMM, HW_Flag_NoRMWSemantics|HW_Flag_FullRangeIMM) HARDWARE_INTRINSIC(AVX_Sqrt, "Sqrt", AVX, -1, 32, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_sqrtps, INS_sqrtpd}, HW_Category_SimpleSIMD, HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_StaticCast, "StaticCast", AVX, -1, 32, 1, {INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movdqa, INS_movaps, INS_movapd}, HW_Category_Helper, HW_Flag_TwoTypeGeneric|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(AVX_Store, "Store", AVX, -1, 32, 2, {INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movdqu, INS_movups, INS_movupd}, HW_Category_MemoryStore, HW_Flag_NoRMWSemantics) diff --git a/src/jit/hwintrinsicxarch.cpp b/src/jit/hwintrinsicxarch.cpp index 869361770c..56c7e99669 100644 --- a/src/jit/hwintrinsicxarch.cpp +++ b/src/jit/hwintrinsicxarch.cpp @@ -124,7 +124,7 @@ InstructionSet Compiler::lookupHWIntrinsicISA(const char* className) // isa -- instruction set of the intrinsic. // // Return Value: -// Id for the hardware intrinsic. +// Id for the hardware intrinsic // // TODO-Throughput: replace sequential search by binary search NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSet isa) @@ -137,6 +137,7 @@ NamedIntrinsic Compiler::lookupHWIntrinsic(const char* methodName, InstructionSe if (isa == hwIntrinsicInfoArray[i].isa && strcmp(methodName, hwIntrinsicInfoArray[i].intrinsicName) == 0) { result = hwIntrinsicInfoArray[i].intrinsicID; + break; } } } @@ -545,7 +546,6 @@ bool Compiler::isFullyImplmentedISAClass(InstructionSet isa) { switch (isa) { - case InstructionSet_SSE2: case InstructionSet_SSE42: case InstructionSet_AVX: case InstructionSet_AVX2: @@ -557,6 +557,7 @@ bool Compiler::isFullyImplmentedISAClass(InstructionSet isa) return false; case InstructionSet_SSE: + case InstructionSet_SSE2: case InstructionSet_SSE3: case InstructionSet_SSSE3: case InstructionSet_SSE41: @@ -929,14 +930,6 @@ GenTree* Compiler::impSSEIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_SSE_SetAllVector128: - assert(sig->numArgs == 1); - assert(getBaseTypeOfSIMDType(sig->retTypeSigClass) == TYP_FLOAT); - op1 = impPopStack().val; - retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op1, gtCloneExpr(op1), gtNewIconNode(0), NI_SSE_Shuffle, - TYP_FLOAT, simdSize); - break; - case NI_SSE_StoreFence: assert(sig->numArgs == 0); assert(JITtype2varType(sig->retType) == TYP_VOID); @@ -1012,6 +1005,16 @@ GenTree* Compiler::impSSE2Intrinsic(NamedIntrinsic intrinsic, break; } + case NI_SSE2_StoreNonTemporal: + { + assert(sig->numArgs == 2); + assert(JITtype2varType(sig->retType) == TYP_VOID); + op2 = impPopStack().val; + op1 = impPopStack().val; + retNode = gtNewSimdHWIntrinsicNode(TYP_VOID, op1, op2, NI_SSE2_StoreNonTemporal, op2->TypeGet(), 0); + break; + } + default: JITDUMP("Not implemented hardware intrinsic"); break; diff --git a/src/jit/instrsxarch.h b/src/jit/instrsxarch.h index 71da647163..c0cd91d6a2 100644 --- a/src/jit/instrsxarch.h +++ b/src/jit/instrsxarch.h @@ -196,6 +196,7 @@ INST3( cvttsd2si, "cvttsd2si" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE #ifndef LEGACY_BACKEND INST3( movntdq, "movntdq" , 0, IUM_WR, 0, 0, PCKDBL(0xE7), BAD_CODE, BAD_CODE) +INST3( movnti, "movnti" , 0, IUM_WR, 0, 0, PCKFLT(0xC3), BAD_CODE, BAD_CODE) INST3( movntpd, "movntpd" , 0, IUM_WR, 0, 0, PCKDBL(0x2B), BAD_CODE, BAD_CODE) INST3( movntps, "movntps" , 0, IUM_WR, 0, 0, PCKFLT(0x2B), BAD_CODE, BAD_CODE) INST3( movdqu, "movdqu" , 0, IUM_WR, 0, 0, SSEFLT(0x7F), BAD_CODE, SSEFLT(0x6F)) @@ -489,6 +490,9 @@ INST3( vpsrlvq, "psrlvq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SS INST3( vpsravd, "psravd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x46)) // Variable Bit Shift Right Arithmetic INST3( vpsllvd, "psllvd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x47)) // Variable Bit Shift Left Logical INST3( vpsllvq, "psllvq" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE38(0x47)) // Variable Bit Shift Left Logical +INST3( vpermilps, "permilps" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x04)) // Permute In-Lane of Quadruples of Single-Precision Floating-Point Values +INST3( vpermilpd, "permilpd" , 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, SSE3A(0x05)) // Permute In-Lane of Quadruples of Double-Precision Floating-Point Values + INST3(LAST_AVX_INSTRUCTION, "LAST_AVX_INSTRUCTION", 0, IUM_WR, 0, 0, BAD_CODE, BAD_CODE, BAD_CODE) // Scalar instructions in SSE4.2 diff --git a/src/jit/lowerarmarch.cpp b/src/jit/lowerarmarch.cpp index b058acbb90..10f182f72a 100644 --- a/src/jit/lowerarmarch.cpp +++ b/src/jit/lowerarmarch.cpp @@ -540,13 +540,6 @@ void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) switch (intrinsicID) { - case NI_ARM64_SIMD_GE_ZERO: - // Unsigned >= 0 ==> Always true - node->gtHWIntrinsicId = setAllVector; - node->gtOp.gtOp1 = comp->gtNewLconNode(~0ULL); - BlockRange().InsertBefore(node, node->gtOp.gtOp1); - BlockRange().Remove(origOp1); - break; case NI_ARM64_SIMD_GT_ZERO: // Unsigned > 0 ==> !(Unsigned == 0) node->gtOp.gtOp1 = @@ -559,12 +552,21 @@ void Lowering::LowerHWIntrinsic(GenTreeHWIntrinsic* node) // Unsigned <= 0 ==> Unsigned == 0 node->gtHWIntrinsicId = NI_ARM64_SIMD_EQ_ZERO; break; + case NI_ARM64_SIMD_GE_ZERO: case NI_ARM64_SIMD_LT_ZERO: + // Unsigned >= 0 ==> Always true // Unsigned < 0 ==> Always false node->gtHWIntrinsicId = setAllVector; - node->gtOp.gtOp1 = comp->gtNewIconNode(0); + node->gtOp.gtOp1 = comp->gtNewLconNode((intrinsicID == NI_ARM64_SIMD_GE_ZERO) ? ~0ULL : 0ULL); BlockRange().InsertBefore(node, node->gtOp.gtOp1); - BlockRange().Remove(origOp1); + if ((origOp1->gtFlags & GTF_ALL_EFFECT) == 0) + { + BlockRange().Remove(origOp1, true); + } + else + { + origOp1->SetUnusedValue(); + } break; default: assert(!"Unhandled LowerCmpUZero case"); diff --git a/src/jit/namedintrinsiclist.h b/src/jit/namedintrinsiclist.h index 91c9720580..f4d7cb2a88 100644 --- a/src/jit/namedintrinsiclist.h +++ b/src/jit/namedintrinsiclist.h @@ -27,8 +27,8 @@ enum NamedIntrinsic : unsigned int #define HARDWARE_INTRINSIC(id, isa, name, form, ins0, ins1, ins2, flags) id, #include "hwintrinsiclistArm64.h" #endif // !defined(_TARGET_XARCH_) && !defined(_TARGET_ARM64_) - NI_HW_INTRINSIC_END -#endif + NI_HW_INTRINSIC_END, +#endif // FEATURE_HW_INTRINSICS }; #if defined(FEATURE_HW_INTRINSICS) && defined(_TARGET_XARCH_) diff --git a/src/mscorlib/System.Private.CoreLib.csproj b/src/mscorlib/System.Private.CoreLib.csproj index 5bc933ce2a..f0c45560fe 100644 --- a/src/mscorlib/System.Private.CoreLib.csproj +++ b/src/mscorlib/System.Private.CoreLib.csproj @@ -297,16 +297,18 @@ <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\X86\Ssse3.PlatformNotSupported.cs" /> </ItemGroup> <ItemGroup Condition="'$(Platform)' == 'arm64'"> - <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Aes.cs" /> + <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Base.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha1.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha256.cs" /> + <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.cs" /> </ItemGroup> <ItemGroup Condition="'$(Platform)' != 'arm64'"> - <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.PlatformNotSupported.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Aes.PlatformNotSupported.cs" /> + <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Base.PlatformNotSupported.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha1.PlatformNotSupported.cs" /> <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Sha256.PlatformNotSupported.cs" /> + <Compile Include="$(BclSourcesRoot)\System\Runtime\Intrinsics\Arm\Arm64\Simd.PlatformNotSupported.cs" /> </ItemGroup> <ItemGroup> <Compile Include="$(BclSourcesRoot)\System\AppContext\AppContext.cs" /> diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs index 8547d7732f..70c65a0f64 100644 --- a/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs +++ b/src/mscorlib/shared/System/Diagnostics/Tracing/EventSource.cs @@ -111,13 +111,13 @@ // // On output there are the following routines // Writing to all listeners that are NOT ETW, we have the following routines -// * WriteToAllListeners(ID, Guid*, COUNT, EventData*) -// * WriteToAllListeners(ID, Guid*, object[]) -// * WriteToAllListeners(NAME, Guid*, EventPayload) +// * WriteToAllListeners(ID, Guid*, Guid*, COUNT, EventData*) +// * WriteToAllListeners(ID, Guid*, Guid*, object[]) +// * WriteToAllListeners(NAME, Guid*, Guid*, EventPayload) // // EventPayload is the internal type that implements the IDictionary<string, object> interface // The EventListeners will pass back for serialized classes for nested object, but -// WriteToAllListeners(NAME, Guid*, EventPayload) unpacks this uses the fields as if they +// WriteToAllListeners(NAME, Guid*, Guid*, EventPayload) unpacks this uses the fields as if they // were parameters to a method. // // The first two are used for the WriteEvent* case, and the later is used for the Write<T> case. @@ -1261,7 +1261,7 @@ namespace System.Diagnostics.Tracing #endif // FEATURE_MANAGED_ETW if (m_Dispatchers != null && m_eventData[eventId].EnabledForAnyListener) - WriteToAllListeners(eventId, relatedActivityId, eventDataCount, data); + WriteToAllListeners(eventId, pActivityId, relatedActivityId, eventDataCount, data); } catch (Exception ex) { @@ -1935,13 +1935,13 @@ namespace System.Diagnostics.Tracing // Maintain old behavior - object identity is preserved if (AppContextSwitches.PreserveEventListnerObjectIdentity) { - WriteToAllListeners(eventId, childActivityID, args); + WriteToAllListeners(eventId, pActivityId, childActivityID, args); } else #endif // !ES_BUILD_STANDALONE { object[] serializedArgs = SerializeEventArgs(eventId, args); - WriteToAllListeners(eventId, childActivityID, serializedArgs); + WriteToAllListeners(eventId, pActivityId, childActivityID, serializedArgs); } } } @@ -2012,7 +2012,7 @@ namespace System.Diagnostics.Tracing #endif //!ES_BUILD_PCL } - private unsafe void WriteToAllListeners(int eventId, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) + private unsafe void WriteToAllListeners(int eventId, Guid* activityID, Guid* childActivityID, int eventDataCount, EventSource.EventData* data) { // We represent a byte[] as a integer denoting the length and then a blob of bytes in the data pointer. This causes a spurious // warning because eventDataCount is off by one for the byte[] case since a byte[] has 2 items associated it. So we want to check @@ -2043,14 +2043,16 @@ namespace System.Diagnostics.Tracing EventSource.EventData* dataPtr = data; for (int i = 0; i < paramCount; i++) args[i] = DecodeObject(eventId, i, ref dataPtr); - WriteToAllListeners(eventId, childActivityID, args); + WriteToAllListeners(eventId, activityID, childActivityID, args); } // helper for writing to all EventListeners attached the current eventSource. - private unsafe void WriteToAllListeners(int eventId, Guid* childActivityID, params object[] args) + private unsafe void WriteToAllListeners(int eventId, Guid* activityID, Guid* childActivityID, params object[] args) { EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); eventCallbackArgs.EventId = eventId; + if (activityID != null) + eventCallbackArgs.ActivityId = *activityID; if (childActivityID != null) eventCallbackArgs.RelatedActivityId = *childActivityID; eventCallbackArgs.EventName = m_eventData[eventId].Name; @@ -4401,7 +4403,20 @@ namespace System.Diagnostics.Tracing /// </summary> public Guid ActivityId { - get { return EventSource.CurrentThreadActivityId; } + get + { + Guid activityId = m_activityId; + if (activityId == Guid.Empty) + { + activityId = EventSource.CurrentThreadActivityId; + } + + return activityId; + } + internal set + { + m_activityId = value; + } } /// <summary> @@ -4576,6 +4591,7 @@ namespace System.Diagnostics.Tracing private string m_eventName; private EventSource m_eventSource; private ReadOnlyCollection<string> m_payloadNames; + private Guid m_activityId; internal EventTags m_tags; internal EventOpcode m_opcode; internal EventLevel m_level; diff --git a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs index 10b378c2b0..ed2690ace0 100644 --- a/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs +++ b/src/mscorlib/shared/System/Diagnostics/Tracing/TraceLogging/TraceLoggingEventSource.cs @@ -671,7 +671,7 @@ namespace System.Diagnostics.Tracing if (m_Dispatchers != null) { var eventData = (EventPayload)(eventTypes.typeInfos[0].GetData(data)); - WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, eventData); + WriteToAllListeners(eventName, ref descriptor, nameInfo.tags, pActivityId, pRelatedActivityId, eventData); } } @@ -700,7 +700,7 @@ namespace System.Diagnostics.Tracing } } - private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, EventPayload payload) + private unsafe void WriteToAllListeners(string eventName, ref EventDescriptor eventDescriptor, EventTags tags, Guid* pActivityId, Guid* pChildActivityId, EventPayload payload) { EventWrittenEventArgs eventCallbackArgs = new EventWrittenEventArgs(this); eventCallbackArgs.EventName = eventName; @@ -712,7 +712,9 @@ namespace System.Diagnostics.Tracing // Self described events do not have an id attached. We mark it internally with -1. eventCallbackArgs.EventId = -1; if (pActivityId != null) - eventCallbackArgs.RelatedActivityId = *pActivityId; + eventCallbackArgs.ActivityId = *pActivityId; + if (pChildActivityId != null) + eventCallbackArgs.RelatedActivityId = *pChildActivityId; if (payload != null) { diff --git a/src/mscorlib/shared/System/Globalization/CompareInfo.cs b/src/mscorlib/shared/System/Globalization/CompareInfo.cs index a288f3657f..ef76c7c75c 100644 --- a/src/mscorlib/shared/System/Globalization/CompareInfo.cs +++ b/src/mscorlib/shared/System/Globalization/CompareInfo.cs @@ -1257,6 +1257,11 @@ namespace System.Globalization throw new ArgumentException(SR.Argument_InvalidFlag, nameof(options)); } + if (_invariantMode) + { + return ((options & CompareOptions.IgnoreCase) != 0) ? TextInfo.GetHashCodeOrdinalIgnoreCase(source) : source.GetHashCode(); + } + return GetHashCodeOfStringCore(source, options); } diff --git a/src/mscorlib/shared/System/IO/PathInternal.cs b/src/mscorlib/shared/System/IO/PathInternal.cs index c5cce00b8f..00a709213f 100644 --- a/src/mscorlib/shared/System/IO/PathInternal.cs +++ b/src/mscorlib/shared/System/IO/PathInternal.cs @@ -123,7 +123,7 @@ namespace System.IO // We treat "\.." , "\." and "\\" as a relative segment. We want to collapse the first separator past the root presuming // the root actually ends in a separator. Otherwise the first segment for RemoveRelativeSegments // in cases like "\\?\C:\.\" and "\\?\C:\..\", the first segment after the root will be ".\" and "..\" which is not considered as a relative segment and hence not be removed. - if (path[skip - 1] == '\\') + if (PathInternal.IsDirectorySeparator(path[skip - 1])) skip--; Span<char> initialBuffer = stackalloc char[260 /* PathInternal.MaxShortPath */]; diff --git a/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs b/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs index a6ec030452..c3ee31a53c 100644 --- a/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs +++ b/src/mscorlib/shared/System/Threading/Tasks/TaskCanceledException.cs @@ -54,6 +54,18 @@ namespace System.Threading.Tasks } /// <summary> + /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/> + /// class with a specified error message, a reference to the inner exception that is the cause of + /// this exception, and the <see cref="CancellationToken"/> that triggered the cancellation. + /// </summary> + /// <param name="message">The error message that explains the reason for the exception.</param> + /// <param name="innerException">The exception that is the cause of the current exception.</param> + /// <param name="token">The <see cref="CancellationToken"/> that triggered the cancellation.</param> + public TaskCanceledException(string message, Exception innerException, CancellationToken token) : base(message, innerException, token) + { + } + + /// <summary> /// Initializes a new instance of the <see cref="T:System.Threading.Tasks.TaskCanceledException"/> class /// with a reference to the <see cref="T:System.Threading.Tasks.Task"/> that has been canceled. /// </summary> diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.PlatformNotSupported.cs b/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.PlatformNotSupported.cs new file mode 100644 index 0000000000..0a13828ee0 --- /dev/null +++ b/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.PlatformNotSupported.cs @@ -0,0 +1,33 @@ +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + + +namespace System.Runtime.Intrinsics.Arm.Arm64 +{ + /// <summary> + /// This class provides access to the Arm64 Base intrinsics + /// + /// These intrinsics are supported by all Arm64 CPUs + /// </summary> + [CLSCompliant(false)] + public static class Base + { + public static bool IsSupported { get { return false; }} + + /// <summary> + /// Vector LeadingSignCount + /// Corresponds to integer forms of ARM64 CLS + /// </summary> + public static int LeadingSignCount(int value) { throw new PlatformNotSupportedException(); } + public static int LeadingSignCount(long value) { throw new PlatformNotSupportedException(); } + + /// <summary> + /// Vector LeadingZeroCount + /// Corresponds to integer forms of ARM64 CLZ + /// </summary> + public static int LeadingZeroCount(int value) { throw new PlatformNotSupportedException(); } + public static int LeadingZeroCount(uint value) { throw new PlatformNotSupportedException(); } + public static int LeadingZeroCount(long value) { throw new PlatformNotSupportedException(); } + public static int LeadingZeroCount(ulong value) { throw new PlatformNotSupportedException(); } + } +} diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.cs b/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.cs new file mode 100644 index 0000000000..fc0a19055e --- /dev/null +++ b/src/mscorlib/src/System/Runtime/Intrinsics/Arm/Arm64/Base.cs @@ -0,0 +1,33 @@ +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; + + +namespace System.Runtime.Intrinsics.Arm.Arm64 +{ + /// <summary> + /// This class provides access to the Arm64 Base intrinsics + /// + /// These intrinsics are supported by all Arm64 CPUs + /// </summary> + [CLSCompliant(false)] + public static class Base + { + public static bool IsSupported { get { return false; }} + + /// <summary> + /// Vector LeadingSignCount + /// Corresponds to integer forms of ARM64 CLS + /// </summary> + public static int LeadingSignCount(int value) => LeadingSignCount(value); + public static int LeadingSignCount(long value) => LeadingSignCount(value); + + /// <summary> + /// Vector LeadingZeroCount + /// Corresponds to integer forms of ARM64 CLZ + /// </summary> + public static int LeadingZeroCount(int value) => LeadingZeroCount(value); + public static int LeadingZeroCount(uint value) => LeadingZeroCount(value); + public static int LeadingZeroCount(long value) => LeadingZeroCount(value); + public static int LeadingZeroCount(ulong value) => LeadingZeroCount(value); + } +} diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse.cs b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse.cs index f07bf4ac99..ecece0bd0a 100644 --- a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse.cs +++ b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse.cs @@ -3,6 +3,7 @@ // See the LICENSE file in the project root for more information. using System; +using System.Runtime.CompilerServices; using System.Runtime.Intrinsics; namespace System.Runtime.Intrinsics.X86 @@ -465,6 +466,25 @@ namespace System.Runtime.Intrinsics.X86 public static Vector128<float> ReciprocalSqrtScalar(Vector128<float> upper, Vector128<float> value) => ReciprocalSqrtScalar(upper, value); /// <summary> + /// __m128 _mm_set1_ps (float a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<float> SetAllVector128(float value) + { + // Zero vector and load value et index 0 + Vector128<float> vector = SetScalarVector128(value); + // Create { vl vl vl vl } and return result + return Shuffle(vector, vector, 0); + } + + /// <summary> + /// __m128 _mm_set_ss (float a) + /// HELPER + /// </summary> + public static Vector128<float> SetScalarVector128(float value) => SetScalarVector128(value); + + /// <summary> /// __m128 _mm_set_ps (float e3, float e2, float e1, float e0) /// </summary> public static unsafe Vector128<float> SetVector128(float e3, float e2, float e1, float e0) @@ -485,18 +505,6 @@ namespace System.Runtime.Intrinsics.X86 } /// <summary> - /// __m128 _mm_set_ss (float a) - /// HELPER - /// </summary> - public static Vector128<float> SetScalarVector128(float value) => SetScalarVector128(value); - - /// <summary> - /// __m128 _mm_set1_ps (float a) - /// HELPER - /// </summary> - public static Vector128<float> SetAllVector128(float value) => SetAllVector128(value); - - /// <summary> /// __m128d _mm_setzero_ps (void) /// HELPER - XORPS /// </summary> diff --git a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse2.cs b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse2.cs index 23d8c93493..d0eb9ef4da 100644 --- a/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse2.cs +++ b/src/mscorlib/src/System/Runtime/Intrinsics/X86/Sse2.cs @@ -969,6 +969,149 @@ namespace System.Runtime.Intrinsics.X86 public static Vector128<byte> PackUnsignedSaturate(Vector128<short> left, Vector128<short> right) => PackUnsignedSaturate(left, right); /// <summary> + /// __m128i _mm_set1_epi8 (char a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<byte> SetAllVector128(byte value) + { + // Zero vector and load value et index 0 + Vector128<byte> vector1 = Sse.StaticCast<uint, byte>(ConvertScalarToVector128UInt32(value)); + // Create { -- -- -- -- -- -- -- -- -- -- -- -- -- -- vl vl } + Vector128<ushort> tmpVector1 = Sse.StaticCast<byte, ushort>(UnpackLow(vector1, vector1)); + // Create { -- -- -- -- -- -- -- -- -- -- -- -- vl vl vl vl } + Vector128<uint> tmpVector2 = Sse.StaticCast<ushort, uint>(UnpackLow(tmpVector1, tmpVector1)); + // Create { vl vl vl vl vl vl vl vl vl vl vl vl vl vl vl vl } and return result + return Sse.StaticCast<uint, byte>(Shuffle(tmpVector2, 0)); + } + /// <summary> + /// __m128i _mm_set1_epi8 (char a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<sbyte> SetAllVector128(sbyte value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<sbyte> vector = Sse.StaticCast<int, sbyte>(ConvertScalarToVector128Int32(value)); + // Create { -- -- -- -- -- -- -- -- -- -- -- -- -- -- vl vl } + Vector128<short> tmpVector1 = Sse.StaticCast<sbyte, short>(UnpackLow(vector, vector)); + // Create { -- -- -- -- -- -- -- -- -- -- -- -- vl vl vl vl } + Vector128<int> tmpVector2 = Sse.StaticCast<short, int>(UnpackLow(tmpVector1, tmpVector1)); + // Create { vl vl vl vl vl vl vl vl vl vl vl vl vl vl vl vl } and return result + return Sse.StaticCast<int, sbyte>(Shuffle(tmpVector2, 0)); + } + /// <summary> + /// __m128i _mm_set1_epi16 (short a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<short> SetAllVector128(short value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<short> vector = Sse.StaticCast<int, short>(ConvertScalarToVector128Int32(value)); + // Create { -- -- -- -- -- -- vl vl } + Vector128<int> tmpVector = Sse.StaticCast<short, int>(UnpackLow(vector, vector)); + // Create { vl vl vl vl vl vl vl vl } and return result + return Sse.StaticCast<int, short>(Shuffle(tmpVector, (byte)0)); + } + /// <summary> + /// __m128i _mm_set1_epi16 (short a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<ushort> SetAllVector128(ushort value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<ushort> vector = Sse.StaticCast<uint, ushort>(ConvertScalarToVector128UInt32(value)); + // Create { -- -- -- -- -- -- vl vl } + Vector128<uint> tmpVector = Sse.StaticCast<ushort, uint>(UnpackLow(vector, vector)); + // Create { vl vl vl vl vl vl vl vl } and return result + return Sse.StaticCast<uint, ushort>(Shuffle(tmpVector, (byte)0)); + } + /// <summary> + /// __m128i _mm_set1_epi32 (int a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<int> SetAllVector128(int value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<int> vector = ConvertScalarToVector128Int32(value); + // Create { vl vl vl vl } and return result + return Shuffle(vector, 0); + } + /// <summary> + /// __m128i _mm_set1_epi32 (int a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<uint> SetAllVector128(uint value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<uint> vector = ConvertScalarToVector128UInt32(value); + // Create { vl vl vl vl } and return result + return Shuffle(vector, 0); + } + /// <summary> + /// __m128i _mm_set1_epi64x (long long a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<long> SetAllVector128(long value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<long> vector = ConvertScalarToVector128Int64(value); + // Create { vl vl } and return result + return UnpackLow(vector, vector); + } + /// <summary> + /// __m128i _mm_set1_epi64x (long long a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<ulong> SetAllVector128(ulong value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<ulong> vector = ConvertScalarToVector128UInt64(value); + // Create { vl vl } and return result + return UnpackLow(vector, vector); + } + /// <summary> + /// __m128d _mm_set1_pd (double a) + /// HELPER + /// </summary> + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128<double> SetAllVector128(double value) + { + // TODO-CQ Optimize algorithm choice based on benchmarks + + // Zero vector and load value et index 0 + Vector128<double> vector = SetScalarVector128(value); + // Create { vl vl } and return result + return UnpackLow(vector, vector); + } + + /// <summary> + /// __m128d _mm_set_sd (double a) + /// HELPER + /// </summary> + public static Vector128<double> SetScalarVector128(double value) => SetScalarVector128(value); + + /// <summary> /// ___m128i _mm_set_epi8 (char e15, char e14, char e13, char e12, char e11, char e10, char e9, char e8, char e7, char e6, char e5, char e4, char e3, char e2, char e1, char e0) /// HELPER /// </summary> @@ -1159,58 +1302,6 @@ namespace System.Runtime.Intrinsics.X86 } /// <summary> - /// __m128d _mm_set_sd (double a) - /// HELPER - /// </summary> - public static Vector128<double> SetScalarVector128(double value) => SetScalarVector128(value); - - /// <summary> - /// __m128i _mm_set1_epi8 (char a) - /// HELPER - /// </summary> - public static Vector128<byte> SetAllVector128(byte value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi8 (char a) - /// HELPER - /// </summary> - public static Vector128<sbyte> SetAllVector128(sbyte value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi16 (short a) - /// HELPER - /// </summary> - public static Vector128<short> SetAllVector128(short value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi16 (short a) - /// HELPER - /// </summary> - public static Vector128<ushort> SetAllVector128(ushort value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi32 (int a) - /// HELPER - /// </summary> - public static Vector128<int> SetAllVector128(int value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi32 (int a) - /// HELPER - /// </summary> - public static Vector128<uint> SetAllVector128(uint value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi64x (long long a) - /// HELPER - /// </summary> - public static Vector128<long> SetAllVector128(long value) => SetAllVector128(value); - /// <summary> - /// __m128i _mm_set1_epi64x (long long a) - /// HELPER - /// </summary> - public static Vector128<ulong> SetAllVector128(ulong value) => SetAllVector128(value); - /// <summary> - /// __m128d _mm_set1_pd (double a) - /// HELPER - /// </summary> - public static Vector128<double> SetAllVector128(double value) => SetAllVector128(value); - - /// <summary> /// __m128i _mm_setzero_si128 () /// HELPER: PXOR /// __m128d _mm_setzero_pd (void) diff --git a/src/utilcode/pedecoder.cpp b/src/utilcode/pedecoder.cpp index ddd65d390d..e5e8ddce67 100644 --- a/src/utilcode/pedecoder.cpp +++ b/src/utilcode/pedecoder.cpp @@ -445,6 +445,7 @@ BOOL PEDecoder::HasWriteableSections() const CONTRACT_CHECK { INSTANCE_CHECK; + PRECONDITION(CheckNTHeaders()); PRECONDITION(CheckFormat()); NOTHROW; GC_NOTRIGGER; @@ -453,7 +454,7 @@ BOOL PEDecoder::HasWriteableSections() const } CONTRACT_CHECK_END; - PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection(FindNTHeaders()); + PTR_IMAGE_SECTION_HEADER pSection = FindFirstSection(); _ASSERTE(pSection != NULL); PTR_IMAGE_SECTION_HEADER pSectionEnd = pSection + VAL16(FindNTHeaders()->FileHeader.NumberOfSections); diff --git a/src/vm/comdelegate.cpp b/src/vm/comdelegate.cpp index bd3a46cbd3..173a8fe6d1 100644 --- a/src/vm/comdelegate.cpp +++ b/src/vm/comdelegate.cpp @@ -214,6 +214,32 @@ public: #endif +#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) +// Return an index of argument slot. First indices are reserved for general purpose registers, +// the following ones for float registers and then the rest for stack slots. +// This index is independent of how many registers are actually used to pass arguments. +int GetNormalizedArgumentSlotIndex(UINT16 offset) +{ + int index; + + if (offset & ShuffleEntry::FPREGMASK) + { + index = NUM_ARGUMENT_REGISTERS + (offset & ShuffleEntry::OFSREGMASK); + } + else if (offset & ShuffleEntry::REGMASK) + { + index = offset & ShuffleEntry::OFSREGMASK; + } + else + { + // stack slot + index = NUM_ARGUMENT_REGISTERS + NUM_FLOAT_ARGUMENT_REGISTERS + (offset & ShuffleEntry::OFSMASK); + } + + return index; +} +#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING + VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<ShuffleEntry> * pShuffleEntryArray) { STANDARD_VM_CONTRACT; @@ -352,6 +378,10 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S ArgLocDesc sArgSrc; ArgLocDesc sArgDst; +#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) + int argSlots = NUM_FLOAT_ARGUMENT_REGISTERS + NUM_ARGUMENT_REGISTERS + sArgPlacerSrc.SizeOfArgStack() / sizeof(size_t); +#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING + // If the target method in non-static (this happens for open instance delegates), we need to account for // the implicit this parameter. if (sSigDst.HasThis()) @@ -367,7 +397,6 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S entry.srcofs = iteratorSrc.GetNextOfs(); entry.dstofs = iteratorDst.GetNextOfs(); - pShuffleEntryArray->Append(entry); } @@ -392,77 +421,80 @@ VOID GenerateShuffleArray(MethodDesc* pInvoke, MethodDesc *pTargetMeth, SArray<S pShuffleEntryArray->Append(entry); } -#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) - // The shuffle entries are produced in two passes on Unix AMD64. The first pass generates shuffle entries for - // all cases except of shuffling struct argument from stack to registers, which is performed in the second pass - // The reason is that if such structure argument contained floating point field and it was followed by a - // floating point argument, generating code for transferring the structure from stack into registers would - // overwrite the xmm register of the floating point argument before it could actually be shuffled. - // For example, consider this case: - // struct S { int x; float y; }; - // void fn(long a, long b, long c, long d, long e, S f, float g); - // src: rdi = this, rsi = a, rdx = b, rcx = c, r8 = d, r9 = e, stack: f, xmm0 = g - // dst: rdi = a, rsi = b, rdx = c, rcx = d, r8 = e, r9 = S.x, xmm0 = s.y, xmm1 = g - for (int pass = 0; pass < 2; pass++) -#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING + // Iterate all the regular arguments. mapping source registers and stack locations to the corresponding + // destination locations. + while ((ofsSrc = sArgPlacerSrc.GetNextOffset()) != TransitionBlock::InvalidOffset) { - // Iterate all the regular arguments. mapping source registers and stack locations to the corresponding - // destination locations. - while ((ofsSrc = sArgPlacerSrc.GetNextOffset()) != TransitionBlock::InvalidOffset) + ofsDst = sArgPlacerDst.GetNextOffset(); + + // Find the argument location mapping for both source and destination signature. A single argument can + // occupy a floating point register, a general purpose register, a pair of registers of any kind or + // a stack slot. + sArgPlacerSrc.GetArgLoc(ofsSrc, &sArgSrc); + sArgPlacerDst.GetArgLoc(ofsDst, &sArgDst); + + ShuffleIterator iteratorSrc(&sArgSrc); + ShuffleIterator iteratorDst(&sArgDst); + + // Shuffle each slot in the argument (register or stack slot) from source to destination. + while (iteratorSrc.HasNextOfs()) { - ofsDst = sArgPlacerDst.GetNextOffset(); + // Locate the next slot to shuffle in the source and destination and encode the transfer into a + // shuffle entry. + entry.srcofs = iteratorSrc.GetNextOfs(); + entry.dstofs = iteratorDst.GetNextOfs(); + + // Only emit this entry if it's not a no-op (i.e. the source and destination locations are + // different). + if (entry.srcofs != entry.dstofs) + pShuffleEntryArray->Append(entry); + } + + // We should have run out of slots to shuffle in the destination at the same time as the source. + _ASSERTE(!iteratorDst.HasNextOfs()); + } #if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) - bool shuffleStructFromStackToRegs = (ofsSrc != TransitionBlock::StructInRegsOffset) && (ofsDst == TransitionBlock::StructInRegsOffset); - if (((pass == 0) && shuffleStructFromStackToRegs) || - ((pass == 1) && !shuffleStructFromStackToRegs)) - { - continue; - } -#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING - // Find the argument location mapping for both source and destination signature. A single argument can - // occupy a floating point register (in which case we don't need to do anything, they're not shuffled) - // or some combination of general registers and the stack. - sArgPlacerSrc.GetArgLoc(ofsSrc, &sArgSrc); - sArgPlacerDst.GetArgLoc(ofsDst, &sArgDst); + // The Unix AMD64 ABI can cause a struct to be passed on stack for the source and in registers for the destination. + // That can cause some arguments that are passed on stack for the destination to be passed in registers in the source. + // An extreme example of that is e.g.: + // void fn(int, int, int, int, int, struct {int, double}, double, double, double, double, double, double, double, double, double, double) + // For this signature, the shuffle needs to move slots as follows (please note the "forward" movement of xmm registers): + // RDI->RSI, RDX->RCX, R8->RDX, R9->R8, stack[0]->R9, xmm0->xmm1, xmm1->xmm2, ... xmm6->xmm7, xmm7->stack[0], stack[1]->xmm0, stack[2]->stack[1], stack[3]->stack[2] + // To prevent overwriting of slots before they are moved, we need to sort the move operations. - ShuffleIterator iteratorSrc(&sArgSrc); - ShuffleIterator iteratorDst(&sArgDst); + NewArrayHolder<bool> filledSlots = new bool[argSlots]; - // Shuffle each slot in the argument (register or stack slot) from source to destination. - while (iteratorSrc.HasNextOfs()) - { - // Locate the next slot to shuffle in the source and destination and encode the transfer into a - // shuffle entry. - entry.srcofs = iteratorSrc.GetNextOfs(); - entry.dstofs = iteratorDst.GetNextOfs(); - - // Only emit this entry if it's not a no-op (i.e. the source and destination locations are - // different). - if (entry.srcofs != entry.dstofs) - pShuffleEntryArray->Append(entry); - } + bool reordered; + do + { + reordered = false; - // We should have run out of slots to shuffle in the destination at the same time as the source. - _ASSERTE(!iteratorDst.HasNextOfs()); + for (int i = 0; i < argSlots; i++) + { + filledSlots[i] = false; } -#if defined(UNIX_AMD64_ABI) && defined(FEATURE_UNIX_AMD64_STRUCT_PASSING) - if (pass == 0) + for (int i = 0; i < pShuffleEntryArray->GetCount(); i++) { - // Reset the iterator for the 2nd pass - sSigSrc.Reset(); - sSigDst.Reset(); + entry = (*pShuffleEntryArray)[i]; - sArgPlacerSrc = ArgIterator(&sSigSrc); - sArgPlacerDst = ArgIterator(&sSigDst); - - if (sSigDst.HasThis()) + // If the slot that we are moving the argument to was filled in already, we need to move this entry in front + // of the entry that filled it in. + if (filledSlots[GetNormalizedArgumentSlotIndex(entry.srcofs)]) { - sArgPlacerSrc.GetNextOffset(); + int j; + for (j = i; (*pShuffleEntryArray)[j].dstofs != entry.srcofs; j--) + (*pShuffleEntryArray)[j] = (*pShuffleEntryArray)[j - 1]; + + (*pShuffleEntryArray)[j] = entry; + reordered = true; } + + filledSlots[GetNormalizedArgumentSlotIndex(entry.dstofs)] = true; } -#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING } + while (reordered); +#endif // UNIX_AMD64_ABI && FEATURE_UNIX_AMD64_STRUCT_PASSING entry.srcofs = ShuffleEntry::SENTINEL; entry.dstofs = 0; diff --git a/src/vm/i386/stublinkerx86.cpp b/src/vm/i386/stublinkerx86.cpp index 28a012e178..ff3ec48d60 100644 --- a/src/vm/i386/stublinkerx86.cpp +++ b/src/vm/i386/stublinkerx86.cpp @@ -3834,28 +3834,56 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) { if (pEntry->srcofs & ShuffleEntry::REGMASK) { - // If source is present in register then destination must also be a register - _ASSERTE(pEntry->dstofs & ShuffleEntry::REGMASK); - // Both the srcofs and dstofs must be of the same kind of registers - float or general purpose. - _ASSERTE((pEntry->dstofs & ShuffleEntry::FPREGMASK) == (pEntry->srcofs & ShuffleEntry::FPREGMASK)); - - int dstRegIndex = pEntry->dstofs & ShuffleEntry::OFSREGMASK; + // Source in a general purpose or float register, destination in the same kind of a register or on stack int srcRegIndex = pEntry->srcofs & ShuffleEntry::OFSREGMASK; - if (pEntry->srcofs & ShuffleEntry::FPREGMASK) + if (pEntry->dstofs & ShuffleEntry::REGMASK) { - // movdqa dstReg, srcReg - X64EmitMovXmmXmm((X86Reg)(kXMM0 + dstRegIndex), (X86Reg)(kXMM0 + srcRegIndex)); + // Source in register, destination in register + + // Both the srcofs and dstofs must be of the same kind of registers - float or general purpose. + _ASSERTE((pEntry->dstofs & ShuffleEntry::FPREGMASK) == (pEntry->srcofs & ShuffleEntry::FPREGMASK)); + int dstRegIndex = pEntry->dstofs & ShuffleEntry::OFSREGMASK; + + if (pEntry->srcofs & ShuffleEntry::FPREGMASK) + { + // movdqa dstReg, srcReg + X64EmitMovXmmXmm((X86Reg)(kXMM0 + dstRegIndex), (X86Reg)(kXMM0 + srcRegIndex)); + } + else + { + // mov dstReg, srcReg + X86EmitMovRegReg(c_argRegs[dstRegIndex], c_argRegs[srcRegIndex]); + } } else { - // mov dstReg, srcReg - X86EmitMovRegReg(c_argRegs[dstRegIndex], c_argRegs[srcRegIndex]); + // Source in register, destination on stack + int dstOffset = (pEntry->dstofs + 1) * sizeof(void*); + + if (pEntry->srcofs & ShuffleEntry::FPREGMASK) + { + if (pEntry->dstofs & ShuffleEntry::FPSINGLEMASK) + { + // movss [rax + dst], srcReg + X64EmitMovSSToMem((X86Reg)(kXMM0 + srcRegIndex), SCRATCH_REGISTER_X86REG, dstOffset); + } + else + { + // movsd [rax + dst], srcReg + X64EmitMovSDToMem((X86Reg)(kXMM0 + srcRegIndex), SCRATCH_REGISTER_X86REG, dstOffset); + } + } + else + { + // mov [rax + dst], srcReg + X86EmitIndexRegStore (SCRATCH_REGISTER_X86REG, dstOffset, c_argRegs[srcRegIndex]); + } } } else if (pEntry->dstofs & ShuffleEntry::REGMASK) { - // source must be on the stack + // Source on stack, destination in register _ASSERTE(!(pEntry->srcofs & ShuffleEntry::REGMASK)); int dstRegIndex = pEntry->dstofs & ShuffleEntry::OFSREGMASK; @@ -3882,10 +3910,8 @@ VOID StubLinkerCPU::EmitShuffleThunk(ShuffleEntry *pShuffleEntryArray) } else { - // source must be on the stack + // Source on stack, destination on stack _ASSERTE(!(pEntry->srcofs & ShuffleEntry::REGMASK)); - - // dest must be on the stack _ASSERTE(!(pEntry->dstofs & ShuffleEntry::REGMASK)); // mov r10, [rax + src] diff --git a/src/vm/peimage.cpp b/src/vm/peimage.cpp index 3536b08361..83989f0e4d 100644 --- a/src/vm/peimage.cpp +++ b/src/vm/peimage.cpp @@ -1029,7 +1029,9 @@ PTR_PEImageLayout PEImage::CreateLayoutFlat(BOOL bPermitWriteableSections) PTR_PEImageLayout pFlatLayout = PEImageLayout::LoadFlat(GetFileHandle(),this); - if (!bPermitWriteableSections && pFlatLayout->HasWriteableSections()) + if (!bPermitWriteableSections + && pFlatLayout->CheckNTHeaders() + && pFlatLayout->HasWriteableSections()) { pFlatLayout->Release(); @@ -1114,8 +1116,7 @@ void PEImage::Load() #ifdef PLATFORM_UNIX if (m_pLayouts[IMAGE_FLAT] != NULL - && m_pLayouts[IMAGE_FLAT]->CheckFormat() - && m_pLayouts[IMAGE_FLAT]->IsILOnly() + && m_pLayouts[IMAGE_FLAT]->CheckILOnlyFormat() && !m_pLayouts[IMAGE_FLAT]->HasWriteableSections()) { // IL-only images with writeable sections are mapped in general way, diff --git a/tests/src/JIT/HardwareIntrinsics/Arm64/Base.cs b/tests/src/JIT/HardwareIntrinsics/Arm64/Base.cs new file mode 100644 index 0000000000..e6efcd04d0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Arm64/Base.cs @@ -0,0 +1,181 @@ +using System; +using System.Diagnostics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm.Arm64; + +namespace Arm64intrisicsTest +{ + class Program + { + static void testUnaryOp<T>(String testCaseDescription, Func<T, int> binOp, Func<T, int> check, T value) + { + bool failed = false; + try + { + int expected = check(value); + int result = binOp(value); + + if (result != expected) + { + Console.WriteLine($"testUnaryOp<{typeof(T).Name}>{testCaseDescription}: Check Failed"); + Console.WriteLine($" result = {result}, expected = {expected}"); + throw new Exception($"testUnaryOp<{typeof(T).Name}>{testCaseDescription}: Failed"); + } + } + catch + { + Console.WriteLine($"testUnaryOp<{typeof(T).Name}>{testCaseDescription}: Unexpected exception"); + throw; + } + } + + static void testThrowsPlatformNotSupported<T>(String testCaseDescription, Func<T, int> unaryOp, T value) + { + bool notSupported = false; + + try + { + unaryOp(value); + } + catch (PlatformNotSupportedException) + { + notSupported = true; + } + catch + { + Console.WriteLine($"testThrowsPlatformNotSupported: Unexpected exception"); + throw; + } + + if (notSupported == false) + { + throw new Exception($"testThrowsPlatformNotSupported<{typeof(T).Name} >{testCaseDescription}: Failed"); + } + } + + static ulong bitsToUint64<T>(T x) + { + return Unsafe.As<T, ulong>(ref x) & ~(~0UL << 8*Unsafe.SizeOf<T>()); + } + + static int leadingZero<T>(T x) + where T : IConvertible + { + ulong compare = 0x1UL << (8*Unsafe.SizeOf<T>() - 1); + int result = 0; + ulong value = bitsToUint64(x); + + while(value < compare) + { + result++; + compare >>= 1; + } + + return result; + + throw new Exception("Unexpected Type"); + } + + static int leadingSign<T>(T x) + where T : IConvertible + { + ulong value = bitsToUint64(x); + ulong signBit = value & (0x1UL << (8*Unsafe.SizeOf<T>() - 1)); + int result = 0; + + if (signBit == 0) + { + result = leadingZero(x); + } + else + { + result = leadingZero((T) Convert.ChangeType(value ^ (signBit + (signBit - 1)), typeof(T))); + } + + return result - 1; + } + + static void TestLeadingSignCount() + { +#if COREFX_HAS_ARM64_BASE + String name = "LeadingSignCount"; + + if (Base.IsSupported) + { + testUnaryOp<int >(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), 0); + testUnaryOp<int >(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), -1); + testUnaryOp<int >(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), 1 << 30); + testUnaryOp<int >(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), -1 << 30); + testUnaryOp<long>(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), 0); + testUnaryOp<long>(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), -1); + testUnaryOp<long>(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), 1L << 60); + testUnaryOp<long>(name, (x) => Base.LeadingSignCount(x), (x) => leadingSign(x), -1L << 60); + } + else + { + testThrowsPlatformNotSupported<int >(name, (x) => Base.LeadingSignCount(x), 0); + testThrowsPlatformNotSupported<long>(name, (x) => Base.LeadingSignCount(x), 0); + } + + Console.WriteLine($"Test{name} passed"); +#endif // COREFX_HAS_ARM64_BASE + } + + static void TestLeadingZeroCount() + { +#if COREFX_HAS_ARM64_BASE + String name = "LeadingZeroCount"; + + if (Base.IsSupported) + { + testUnaryOp<int >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 0); + testUnaryOp<int >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), -1); + testUnaryOp<int >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 1 << 30); + testUnaryOp<int >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), -1 << 30); + testUnaryOp<uint >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 0); + testUnaryOp<uint >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 1 << 30); + testUnaryOp<long >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 0); + testUnaryOp<long >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), -1); + testUnaryOp<long >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 1L << 60); + testUnaryOp<long >(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), -1L << 60); + testUnaryOp<ulong>(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 0); + testUnaryOp<ulong>(name, (x) => Base.LeadingZeroCount(x), (x) => leadingZero(x), 1L << 60); + } + else + { + testThrowsPlatformNotSupported<int >(name, (x) => Base.LeadingZeroCount(x), 0); + testThrowsPlatformNotSupported<uint >(name, (x) => Base.LeadingZeroCount(x), 0); + testThrowsPlatformNotSupported<long >(name, (x) => Base.LeadingZeroCount(x), 0); + testThrowsPlatformNotSupported<ulong>(name, (x) => Base.LeadingZeroCount(x), 0); + } + + Console.WriteLine($"Test{name} passed"); +#endif // COREFX_HAS_ARM64_BASE + } + + static void ExecuteAllTests() + { + TestLeadingSignCount(); + TestLeadingZeroCount(); + } + + static int Main(string[] args) + { +#if COREFX_HAS_ARM64_BASE + Console.WriteLine($"System.Runtime.Intrinsics.Arm.Arm64.Base.IsSupported = {Base.IsSupported}"); + + // Reflection call + var issupported = "get_IsSupported"; + bool reflectedIsSupported = Convert.ToBoolean(typeof(Base).GetMethod(issupported).Invoke(null, null)); + + Debug.Assert(reflectedIsSupported == Base.IsSupported, "Reflection result does not match"); +#endif // COREFX_HAS_ARM64_BASE + + ExecuteAllTests(); + + return 100; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/Arm64/Base.csproj b/tests/src/JIT/HardwareIntrinsics/Arm64/Base.csproj new file mode 100644 index 0000000000..45dd4b6451 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/Arm64/Base.csproj @@ -0,0 +1,36 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="Base.cs" /> + </ItemGroup> + <ItemGroup> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj index e42b861672..e1d1a8d9e3 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_r.csproj @@ -74,6 +74,10 @@ <Compile Include="Multiply.Single.cs" /> <Compile Include="Or.Double.cs" /> <Compile Include="Or.Single.cs" /> + <Compile Include="Permute.Single.1.cs" /> + <Compile Include="Permute.Double.1.cs" /> + <Compile Include="Permute.Single.2.cs" /> + <Compile Include="Permute.Double.2.cs" /> <Compile Include="RoundCurrentDirection.Double.cs" /> <Compile Include="RoundCurrentDirection.Single.cs" /> <Compile Include="RoundToNearestInteger.Double.cs" /> @@ -84,6 +88,8 @@ <Compile Include="RoundToPositiveInfinity.Single.cs" /> <Compile Include="RoundToZero.Double.cs" /> <Compile Include="RoundToZero.Single.cs" /> + <Compile Include="Shuffle.Single.1.cs" /> + <Compile Include="Shuffle.Double.1.cs" /> <Compile Include="Subtract.Double.cs" /> <Compile Include="Subtract.Single.cs" /> <Compile Include="TestC.Byte.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj index 554c0451e2..4dd281b38b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Avx_ro.csproj @@ -74,6 +74,10 @@ <Compile Include="Multiply.Single.cs" /> <Compile Include="Or.Double.cs" /> <Compile Include="Or.Single.cs" /> + <Compile Include="Permute.Single.1.cs" /> + <Compile Include="Permute.Double.1.cs" /> + <Compile Include="Permute.Single.2.cs" /> + <Compile Include="Permute.Double.2.cs" /> <Compile Include="RoundCurrentDirection.Double.cs" /> <Compile Include="RoundCurrentDirection.Single.cs" /> <Compile Include="RoundToNearestInteger.Double.cs" /> @@ -84,6 +88,8 @@ <Compile Include="RoundToPositiveInfinity.Single.cs" /> <Compile Include="RoundToZero.Double.cs" /> <Compile Include="RoundToZero.Single.cs" /> + <Compile Include="Shuffle.Single.1.cs" /> + <Compile Include="Shuffle.Double.1.cs" /> <Compile Include="Subtract.Double.cs" /> <Compile Include="Subtract.Single.cs" /> <Compile Include="TestC.Byte.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.1.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.1.cs new file mode 100644 index 0000000000..1abf18d52c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.1.cs @@ -0,0 +1,313 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteDouble1() + { + var test = new SimpleUnaryOpTest__PermuteDouble1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__PermuteDouble1 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector256<Double> _clsVar; + + private Vector256<Double> _fld; + + private SimpleUnaryOpTest__DataTable<Double, Double> _dataTable; + + static SimpleUnaryOpTest__PermuteDouble1() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar), ref Unsafe.As<Double, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__PermuteDouble1() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld), ref Unsafe.As<Double, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable<Double, Double>(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute( + Unsafe.Read<Vector256<Double>>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute( + Avx.LoadVector256((Double*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute( + Avx.LoadAlignedVector256((Double*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Double>>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Double*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Double*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector256<Double>>(_dataTable.inArrayPtr); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Avx.LoadVector256((Double*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Avx.LoadAlignedVector256((Double*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__PermuteDouble1(); + var result = Avx.Permute(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Double> firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[1])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2]) || BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute)}<Double>(Vector256<Double><9>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.2.cs new file mode 100644 index 0000000000..37722b50c3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Double.2.cs @@ -0,0 +1,313 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteDouble2() + { + var test = new SimpleUnaryOpTest__PermuteDouble2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__PermuteDouble2 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data = new Double[Op1ElementCount]; + + private static Vector128<Double> _clsVar; + + private Vector128<Double> _fld; + + private SimpleUnaryOpTest__DataTable<Double, Double> _dataTable; + + static SimpleUnaryOpTest__PermuteDouble2() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar), ref Unsafe.As<Double, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__PermuteDouble2() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld), ref Unsafe.As<Double, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable<Double, Double>(_data, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute( + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__PermuteDouble2(); + var result = Avx.Permute(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Double> firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Double[] inArray = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[1]) != BitConverter.DoubleToInt64Bits(firstOp[1])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute)}<Double>(Vector128<Double><9>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.1.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.1.cs new file mode 100644 index 0000000000..69a7466967 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.1.cs @@ -0,0 +1,313 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteSingle1() + { + var test = new SimpleUnaryOpTest__PermuteSingle1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__PermuteSingle1 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector256<Single> _clsVar; + + private Vector256<Single> _fld; + + private SimpleUnaryOpTest__DataTable<Single, Single> _dataTable; + + static SimpleUnaryOpTest__PermuteSingle1() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar), ref Unsafe.As<Single, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__PermuteSingle1() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld), ref Unsafe.As<Single, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable<Single, Single>(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute( + Unsafe.Read<Vector256<Single>>(_dataTable.inArrayPtr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute( + Avx.LoadVector256((Single*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute( + Avx.LoadAlignedVector256((Single*)(_dataTable.inArrayPtr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Single>>(_dataTable.inArrayPtr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Single*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Single*)(_dataTable.inArrayPtr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute( + _clsVar, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector256<Single>>(_dataTable.inArrayPtr); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Avx.LoadVector256((Single*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Avx.LoadAlignedVector256((Single*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__PermuteSingle1(); + var result = Avx.Permute(test._fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute(_fld, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Single> firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(firstOp[1])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[4]) != BitConverter.SingleToInt32Bits(firstOp[5])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute)}<Single>(Vector256<Single><9>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.2.cs new file mode 100644 index 0000000000..f30023e5e3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Permute.Single.2.cs @@ -0,0 +1,313 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void PermuteSingle2() + { + var test = new SimpleUnaryOpTest__PermuteSingle2(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Sse.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleUnaryOpTest__PermuteSingle2 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data = new Single[Op1ElementCount]; + + private static Vector128<Single> _clsVar; + + private Vector128<Single> _fld; + + private SimpleUnaryOpTest__DataTable<Single, Single> _dataTable; + + static SimpleUnaryOpTest__PermuteSingle2() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Single>, byte>(ref _clsVar), ref Unsafe.As<Single, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__PermuteSingle2() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Single>, byte>(ref _fld), ref Unsafe.As<Single, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleUnaryOpTest__DataTable<Single, Single>(_data, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Permute( + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Permute( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Permute( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)), + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Permute), new Type[] { typeof(Vector128<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)), + (byte)2 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Permute( + _clsVar, + 2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx.Permute(firstOp, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__PermuteSingle2(); + var result = Avx.Permute(test._fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Permute(_fld, 2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Single> firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Single[] inArray = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(firstOp[2])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[1]) != BitConverter.SingleToInt32Bits(firstOp[0]) || BitConverter.SingleToInt32Bits(result[2]) != BitConverter.SingleToInt32Bits(firstOp[0])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Permute)}<Single>(Vector128<Single><9>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs index c2c23a518c..d74b22f5e5 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Program.Avx.cs @@ -59,6 +59,10 @@ namespace JIT.HardwareIntrinsics.X86 ["Multiply.Single"] = MultiplySingle, ["Or.Double"] = OrDouble, ["Or.Single"] = OrSingle, + ["Permute.Single.1"] = PermuteSingle1, + ["Permute.Double.1"] = PermuteDouble1, + ["Permute.Single.2"] = PermuteSingle2, + ["Permute.Double.2"] = PermuteDouble2, ["RoundCurrentDirection.Double"] = RoundCurrentDirectionDouble, ["RoundCurrentDirection.Single"] = RoundCurrentDirectionSingle, ["RoundToNearestInteger.Double"] = RoundToNearestIntegerDouble, @@ -69,6 +73,8 @@ namespace JIT.HardwareIntrinsics.X86 ["RoundToPositiveInfinity.Single"] = RoundToPositiveInfinitySingle, ["RoundToZero.Double"] = RoundToZeroDouble, ["RoundToZero.Single"] = RoundToZeroSingle, + ["Shuffle.Single.1"] = ShuffleSingle1, + ["Shuffle.Double.1"] = ShuffleDouble1, ["Subtract.Double"] = SubtractDouble, ["Subtract.Single"] = SubtractSingle, ["TestC.Byte"] = TestCByte, diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Double.1.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Double.1.cs new file mode 100644 index 0000000000..7577826ec8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Double.1.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ShuffleDouble1() + { + var test = new SimpleBinaryOpTest__ShuffleDouble1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShuffleDouble1 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Double); + private const int Op2ElementCount = VectorSize / sizeof(Double); + private const int RetElementCount = VectorSize / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + private static Double[] _data2 = new Double[Op2ElementCount]; + + private static Vector256<Double> _clsVar1; + private static Vector256<Double> _clsVar2; + + private Vector256<Double> _fld1; + private Vector256<Double> _fld2; + + private SimpleBinaryOpTest__DataTable<Double, Double, Double> _dataTable; + + static SimpleBinaryOpTest__ShuffleDouble1() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__ShuffleDouble1() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (double)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Double, Double, Double>(_data1, _data2, new Double[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Shuffle( + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Shuffle( + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Shuffle( + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Double>), typeof(Vector256<Double>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Shuffle( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Double>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Double>>(_dataTable.inArray2Ptr); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Double*)(_dataTable.inArray2Ptr)); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__ShuffleDouble1(); + var result = Avx.Shuffle(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Shuffle(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Double> left, Vector256<Double> right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] inArray2 = new Double[Op2ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Double, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "") + { + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(left[1])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[3]) != BitConverter.DoubleToInt64Bits(right[2])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Shuffle)}<Double>(Vector256<Double>.1, Vector256<Double>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Single.1.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Single.1.cs new file mode 100644 index 0000000000..b3fa1cd1a4 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/Shuffle.Single.1.cs @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void ShuffleSingle1() + { + var test = new SimpleBinaryOpTest__ShuffleSingle1(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Avx.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__ShuffleSingle1 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Single); + private const int Op2ElementCount = VectorSize / sizeof(Single); + private const int RetElementCount = VectorSize / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + private static Single[] _data2 = new Single[Op2ElementCount]; + + private static Vector256<Single> _clsVar1; + private static Vector256<Single> _clsVar2; + + private Vector256<Single> _fld1; + private Vector256<Single> _fld2; + + private SimpleBinaryOpTest__DataTable<Single, Single, Single> _dataTable; + + static SimpleBinaryOpTest__ShuffleSingle1() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar1), ref Unsafe.As<Single, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _clsVar2), ref Unsafe.As<Single, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__ShuffleSingle1() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld1), ref Unsafe.As<Single, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector256<Single>, byte>(ref _fld2), ref Unsafe.As<Single, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = (float)(random.NextDouble()); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = (float)(random.NextDouble()); } + _dataTable = new SimpleBinaryOpTest__DataTable<Single, Single, Single>(_data1, _data2, new Single[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx.Shuffle( + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx.Shuffle( + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx.Shuffle( + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)), + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr), + Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx).GetMethod(nameof(Avx.Shuffle), new Type[] { typeof(Vector256<Single>), typeof(Vector256<Single>), typeof(byte) }) + .Invoke(null, new object[] { + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)), + Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)), + (byte)1 + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx.Shuffle( + _clsVar1, + _clsVar2, + 1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<Vector256<Single>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<Vector256<Single>>(_dataTable.inArray2Ptr); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = Avx.LoadVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray1Ptr)); + var right = Avx.LoadAlignedVector256((Single*)(_dataTable.inArray2Ptr)); + var result = Avx.Shuffle(left, right, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__ShuffleSingle1(); + var result = Avx.Shuffle(test._fld1, test._fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx.Shuffle(_fld1, _fld2, 1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256<Single> left, Vector256<Single> right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] inArray2 = new Single[Op2ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Single, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Single[] left, Single[] right, Single[] result, [CallerMemberName] string method = "") + { + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(left[1])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[7]) != BitConverter.SingleToInt32Bits(right[4])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx)}.{nameof(Avx.Shuffle)}<Single>(Vector256<Single>.1, Vector256<Single>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index e56cf611cf..bd64a8e9c2 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -424,6 +424,10 @@ private static readonly (string templateFileName, Dictionary<string, string> tem ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Multiply", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["NextValueOp2"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["NextValueOp2"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "(BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "(BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Or", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["NextValueOp2"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "(BitConverter.SingleToInt32Bits(left[0]) | BitConverter.SingleToInt32Bits(right[0])) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "(BitConverter.SingleToInt32Bits(left[i]) | BitConverter.SingleToInt32Bits(right[i])) != BitConverter.SingleToInt32Bits(result[i])"}), + ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Imm"] = "1", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(firstOp[1])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[4]) != BitConverter.SingleToInt32Bits(firstOp[5])"}), + ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Permute", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Imm"] = "1", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[1])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2]) || BitConverter.DoubleToInt64Bits(result[2]) != BitConverter.DoubleToInt64Bits(firstOp[2])"}), + ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Sse", ["Method"] = "Permute", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Single", ["Imm"] = "2", ["VectorSize"] = "16", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(firstOp[2])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[1]) != BitConverter.SingleToInt32Bits(firstOp[0]) || BitConverter.SingleToInt32Bits(result[2]) != BitConverter.SingleToInt32Bits(firstOp[0])"}), + ("ImmUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Sse2",["Method"] = "Permute", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Imm"] = "2", ["VectorSize"] = "16", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(firstOp[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[1]) != BitConverter.DoubleToInt64Bits(firstOp[1])"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundCurrentDirection", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToNearestInteger", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[i], MidpointRounding.AwayFromZero))"}), @@ -434,6 +438,8 @@ private static readonly (string templateFileName, Dictionary<string, string> tem ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToPositiveInfinity", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToZero", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits((firstOp[0] > 0) ? Math.Floor(firstOp[0]) : Math.Ceiling(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits((firstOp[i] > 0) ? Math.Floor(firstOp[i]) : Math.Ceiling(firstOp[i]))"}), ("SimpleUnOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "RoundToZero", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits((firstOp[0] > 0) ? MathF.Floor(firstOp[0]) : MathF.Ceiling(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits((firstOp[i] > 0) ? MathF.Floor(firstOp[i]) : MathF.Ceiling(firstOp[i]))"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Shuffle", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Single", ["Imm"] = "1", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["NextValueOp2"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(left[1])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[7]) != BitConverter.SingleToInt32Bits(right[4])"}), + ("ImmBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Shuffle", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["Imm"] = "1", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["NextValueOp2"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(left[1])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[3]) != BitConverter.DoubleToInt64Bits(right[2])"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Subtract", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Double", ["VectorSize"] = "32", ["NextValueOp1"] = "(double)(random.NextDouble())", ["NextValueOp2"] = "(double)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i] - right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "Subtract", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Single", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Single", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Single", ["VectorSize"] = "32", ["NextValueOp1"] = "(float)(random.NextDouble())", ["NextValueOp2"] = "(float)(random.NextDouble())", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(left[0] - right[0]) != BitConverter.SingleToInt32Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(left[i] - right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), ("BooleanBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Avx", ["LoadIsa"] = "Avx", ["Method"] = "TestC", ["RetVectorType"] = "Vector256", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector256", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector256", ["Op2BaseType"] = "Byte", ["VectorSize"] = "32", ["NextValueOp1"] = "(byte)(random.Next(0, byte.MaxValue))", ["NextValueOp2"] = "(byte)(random.Next(0, byte.MaxValue))", ["ValidateFirstResult"] = "(~left[i] & right[i]) == 0"}), @@ -632,7 +638,7 @@ namespace JIT.HardwareIntrinsics.X86 private static bool isImmTemplate(string name) { return name == "ImmUnOpTest.template" || name == "InsertScalarTest.template" || - name == "ExtractScalarTest.template"; + name == "ExtractScalarTest.template" || name == "ImmBinOpTest.template"; } private static void ProcessInput(StreamWriter testListFile, (string templateFileName, Dictionary<string, string> templateData) input) diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/ImmBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ImmBinOpTest.template new file mode 100644 index 0000000000..e24445932a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ImmBinOpTest.template @@ -0,0 +1,337 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void {Method}{RetBaseType}{Imm}() + { + var test = new SimpleBinaryOpTest__{Method}{RetBaseType}{Imm}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({LoadIsa}.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__{Method}{RetBaseType}{Imm} + { + private const int VectorSize = {VectorSize}; + + private const int Op1ElementCount = VectorSize / sizeof({Op1BaseType}); + private const int Op2ElementCount = VectorSize / sizeof({Op2BaseType}); + private const int RetElementCount = VectorSize / sizeof({RetBaseType}); + + private static {Op1BaseType}[] _data1 = new {Op1BaseType}[Op1ElementCount]; + private static {Op2BaseType}[] _data2 = new {Op2BaseType}[Op2ElementCount]; + + private static {Op1VectorType}<{Op1BaseType}> _clsVar1; + private static {Op2VectorType}<{Op2BaseType}> _clsVar2; + + private {Op1VectorType}<{Op1BaseType}> _fld1; + private {Op2VectorType}<{Op2BaseType}> _fld2; + + private SimpleBinaryOpTest__DataTable<{RetBaseType}, {Op1BaseType}, {Op2BaseType}> _dataTable; + + static SimpleBinaryOpTest__{Method}{RetBaseType}{Imm}() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _clsVar1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _clsVar2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), VectorSize); + } + + public SimpleBinaryOpTest__{Method}{RetBaseType}{Imm}() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1VectorType}<{Op1BaseType}>, byte>(ref _fld1), ref Unsafe.As<{Op1BaseType}, byte>(ref _data1[0]), VectorSize); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2VectorType}<{Op2BaseType}>, byte>(ref _fld2), ref Unsafe.As<{Op2BaseType}, byte>(ref _data2[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = {NextValueOp1}; } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = {NextValueOp2}; } + _dataTable = new SimpleBinaryOpTest__DataTable<{RetBaseType}, {Op1BaseType}, {Op2BaseType}>(_data1, _data2, new {RetBaseType}[RetElementCount], VectorSize); + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = {Isa}.{Method}( + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = {Isa}.{Method}( + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = {Isa}.{Method}( + {LoadIsa}.LoadAligned{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.LoadAligned{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr), + Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1VectorType}<{Op1BaseType}>), typeof({Op2VectorType}<{Op2BaseType}>), typeof(byte) }) + .Invoke(null, new object[] { + {LoadIsa}.LoadAligned{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)), + {LoadIsa}.LoadAligned{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)), + (byte){Imm} + }); + + Unsafe.Write(_dataTable.outArrayPtr, ({RetVectorType}<{RetBaseType}>)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = {Isa}.{Method}( + _clsVar1, + _clsVar2, + {Imm} + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var left = Unsafe.Read<{Op1VectorType}<{Op1BaseType}>>(_dataTable.inArray1Ptr); + var right = Unsafe.Read<{Op2VectorType}<{Op2BaseType}>>(_dataTable.inArray2Ptr); + var result = {Isa}.{Method}(left, right, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var left = {LoadIsa}.Load{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var right = {LoadIsa}.Load{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)); + var result = {Isa}.{Method}(left, right, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var left = {LoadIsa}.LoadAligned{Op1VectorType}(({Op1BaseType}*)(_dataTable.inArray1Ptr)); + var right = {LoadIsa}.LoadAligned{Op2VectorType}(({Op2BaseType}*)(_dataTable.inArray2Ptr)); + var result = {Isa}.{Method}(left, right, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__{Method}{RetBaseType}{Imm}(); + var result = {Isa}.{Method}(test._fld1, test._fld2, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = {Isa}.{Method}(_fld1, _fld2, {Imm}); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult({Op1VectorType}<{Op1BaseType}> left, {Op2VectorType}<{Op2BaseType}> right, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + {Op1BaseType}[] inArray1 = new {Op1BaseType}[Op1ElementCount]; + {Op2BaseType}[] inArray2 = new {Op2BaseType}[Op2ElementCount]; + {RetBaseType}[] outArray = new {RetBaseType}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op1BaseType}, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{Op2BaseType}, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{RetBaseType}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult({Op1BaseType}[] left, {Op2BaseType}[] right, {RetBaseType}[] result, [CallerMemberName] string method = "") + { + if ({ValidateFirstResult}) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ({ValidateRemainingResults}) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1VectorType}<{Op1BaseType}>.{Imm}, {Op2VectorType}<{Op2BaseType}>): {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128Int64.cs index eb4c5488ab..5ee35f0c17 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128Int64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128Int64.cs @@ -52,6 +52,11 @@ namespace IntelHardwareIntrinsicTest { } + catch(Exception ex) + { + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.ConvertScalarToVector128Int64)}-{ex} failed: expected PlatformNotSupportedException exception."); + } } } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128UInt64.cs index f75cc86aea..361f98eaf2 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128UInt64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/ConvertScalarToVector128UInt64.cs @@ -26,10 +26,10 @@ namespace IntelHardwareIntrinsicTest { if (Environment.Is64BitProcess) { - var vd = Sse2.ConvertScalarToVector128UInt64((ulong)5); + var vd = Sse2.ConvertScalarToVector128UInt64(0xffffffff01ul); Unsafe.Write(ulongTable.outArrayPtr, vd); - if (!ulongTable.CheckResult((x, y) => (y[0] == 5) && (y[1] == 0))) + if (!ulongTable.CheckResult((x, y) => (y[0] == 0xffffffff01ul) && (y[1] == 0))) { Console.WriteLine("SSE ConvertScalarToVector128Single failed on ulong:"); foreach (var item in ulongTable.outArray) @@ -52,6 +52,11 @@ namespace IntelHardwareIntrinsicTest { } + catch(Exception ex) + { + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.ConvertScalarToVector128UInt64)}-{ex} failed: expected PlatformNotSupportedException exception."); + } } } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128.cs new file mode 100644 index 0000000000..d379720ddf --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128.cs @@ -0,0 +1,301 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + internal static partial class Program + { + private const int Pass = 100; + private const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + int testsCount = 21; + string methodUnderTestName = nameof(Sse2.SetAllVector128); + + if (Sse2.IsSupported) + { + using (var doubleTable = TestTableSse2<double>.Create(testsCount)) + using (var longTable = TestTableSse2<long>.Create(testsCount)) + using (var ulongTable = TestTableSse2<ulong>.Create(testsCount)) + using (var intTable = TestTableSse2<int>.Create(testsCount)) + using (var uintTable = TestTableSse2<uint>.Create(testsCount)) + using (var shortTable = TestTableSse2<short>.Create(testsCount)) + using (var ushortTable = TestTableSse2<ushort>.Create(testsCount)) + using (var sbyteTable = TestTableSse2<sbyte>.Create(testsCount)) + using (var byteTable = TestTableSse2<byte>.Create(testsCount)) + { + for (double i = 0; i < testsCount; i += 1) + { + Vector128<double> result = Sse2.SetAllVector128(i); + doubleTable.SetOutArray(result, (int)i); + } + + if (Environment.Is64BitProcess) + { + for (long i = 0; i < testsCount; i++) + { + Vector128<long> result = Sse2.SetAllVector128(i); + longTable.SetOutArray(result, (int)i); + } + + for (ulong i = 0; i < (ulong)testsCount; i++) + { + Vector128<ulong> result = Sse2.SetAllVector128(i); + ulongTable.SetOutArray(result, (int)i); + } + } + else + { + try + { + var vd = Sse2.SetAllVector128((long)0xffffl); + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.SetAllVector128)} failed for long: expected PlatformNotSupportedException exception."); + } + catch (PlatformNotSupportedException) + { + + } + + try + { + var vd = Sse2.SetAllVector128((ulong)0xfffful); + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.SetAllVector128)} failed for ulong: expected PlatformNotSupportedException exception."); + } + catch (PlatformNotSupportedException) + { + + } + } + + + + for (int i = 0; i < testsCount; i++) + { + Vector128<int> result = Sse2.SetAllVector128((int)i); + intTable.SetOutArray(result, i); + } + + for (uint i = 0; i < testsCount; i++) + { + Vector128<uint> result = Sse2.SetAllVector128(i); + uintTable.SetOutArray(result, (int)i); + } + + for (int i = 0; i < testsCount; i++) + { + Vector128<short> result = Sse2.SetAllVector128((short)i); + shortTable.SetOutArray(result, i); + } + + for (int i = 0; i < testsCount; i++) + { + Vector128<ushort> result = Sse2.SetAllVector128((ushort)i); + ushortTable.SetOutArray(result, i); + } + + for (int i = 0; i < testsCount; i++) + { + Vector128<sbyte> result = Sse2.SetAllVector128((sbyte)i); + sbyteTable.SetOutArray(result, i); + } + + for (int i = 0; i < testsCount; i++) + { + Vector128<byte> result = Sse2.SetAllVector128((byte)i); + byteTable.SetOutArray(result, i); + } + + double doubleCounter = 0.0; + CheckMethodSpan<double> checkDouble = (Span<double> x, Span<double> y, Span<double> z, Span<double> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != doubleCounter) + result = false; + } + doubleCounter += 1; + return result; + }; + + if (!doubleTable.CheckResult(checkDouble)) + { + PrintError(doubleTable, methodUnderTestName, "(double x, double y, double z, ref double a) => (a = BitwiseXor(x, y)) == z", checkDouble); + testResult = Fail; + } + + if (Environment.Is64BitProcess) + { + long longCounter = 0; + CheckMethodSpan<long> checkInt64 = (Span<long> x, Span<long> y, Span<long> z, Span<long> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != longCounter) + result = false; + } + longCounter++; + return result; + }; + + if (!longTable.CheckResult(checkInt64)) + { + PrintError(longTable, methodUnderTestName, "(long x, long y, long z, ref long a) => (a = x ^ y) == z", checkInt64); + testResult = Fail; + } + + ulong ulongCounter = 0; + CheckMethodSpan<ulong> checkUInt64 = (Span<ulong> x, Span<ulong> y, Span<ulong> z, Span<ulong> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != ulongCounter) + result = false; + } + ulongCounter++; + return result; + }; + + if (!ulongTable.CheckResult(checkUInt64)) + { + PrintError(ulongTable, methodUnderTestName, "(Span<ulong> x, Span<ulong> y, Span<ulong> z, Span<ulong> a) => SetAllVector128", checkUInt64); + testResult = Fail; + } + } + + int intCounter = 0; + CheckMethodSpan<int> checkInt32 = (Span<int> x, Span<int> y, Span<int> z, Span<int> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != intCounter) + result = false; + } + intCounter++; + return result; + }; + + if (!intTable.CheckResult(checkInt32)) + { + PrintError(intTable, methodUnderTestName, "(int x, int y, int z, ref int a) => (a = x ^ y) == z", checkInt32); + testResult = Fail; + } + + uint uintCounter = 0; + CheckMethodSpan<uint> checkUInt32 = (Span<uint> x, Span<uint> y, Span<uint> z, Span<uint> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != uintCounter) + result = false; + } + uintCounter++; + return result; + }; + + if (!uintTable.CheckResult(checkUInt32)) + { + PrintError(uintTable, methodUnderTestName, "(uint x, uint y, uint z, ref uint a) => (a = x ^ y) == z", checkUInt32); + testResult = Fail; + } + + int shortCounter = 0; + CheckMethodSpan<short> checkInt16 = (Span<short> x, Span<short> y, Span<short> z, Span<short> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != shortCounter) + result = false; + } + shortCounter++; + return result; + }; + + if (!shortTable.CheckResult(checkInt16)) + { + PrintError(shortTable, methodUnderTestName, "(short x, short y, short z, ref short a) => (a = (short)(x ^ y)) == z", checkInt16); + testResult = Fail; + } + + int ushortCounter = 0; + CheckMethodSpan<ushort> checkUInt16 = (Span<ushort> x, Span<ushort> y, Span<ushort> z, Span<ushort> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != ushortCounter) + result = false; + } + ushortCounter++; + return result; + }; + + if (!ushortTable.CheckResult(checkUInt16)) + { + PrintError(ushortTable, methodUnderTestName, "(ushort x, ushort y, ushort z, ref ushort a) => (a = (ushort)(x ^ y)) == z", checkUInt16); + testResult = Fail; + } + + int sbyteCounter = 0; + CheckMethodSpan<sbyte> checkSByte = (Span<sbyte> x, Span<sbyte> y, Span<sbyte> z, Span<sbyte> a) => + { + bool result = true; + for (int i = 0; i < z.Length; i++) + { + if (z[i] != sbyteCounter) + result = false; + } + sbyteCounter++; + return result; + }; + + if (!sbyteTable.CheckResult(checkSByte)) + { + PrintError(sbyteTable, methodUnderTestName, "(sbyte x, sbyte y, sbyte z, ref sbyte a) => (a = (sbyte)(x ^ y)) == z", checkSByte); + testResult = Fail; + } + + int byteCounter = 0; + CheckMethodSpan<byte> checkByte = (Span<byte> x, Span<byte> y, Span<byte> z, Span<byte> a) => + { + bool result = true; + for (int i = 0; i < x.Length; i++) + { + if (z[i] != byteCounter) + result = false; + } + byteCounter++; + return result; + }; + + if (!byteTable.CheckResult(checkByte)) + { + PrintError(byteTable, methodUnderTestName, "(byte x, byte y, byte z, ref byte a) => (a = (byte)(x ^ y)) == z", checkByte); + testResult = Fail; + } + } + } + else + { + Console.WriteLine($"Sse2.IsSupported: {Sse2.IsSupported}, skipped tests of {typeof(Sse2)}.{methodUnderTestName}"); + } + + return testResult; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_r.csproj new file mode 100644 index 0000000000..8ff187b439 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_r.csproj @@ -0,0 +1,38 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{8156C540-D3A7-4B4A-B513-3C638EC9088A}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize> + </Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="SetAllVector128.cs" /> + <Compile Include="TestTableSse2.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_ro.csproj new file mode 100644 index 0000000000..f63ed35b08 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SetAllVector128_ro.csproj @@ -0,0 +1,37 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{4A5D16DC-6AFD-4BCC-929F-08EFDF76298E}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="SetAllVector128.cs" /> + <Compile Include="TestTableSse2.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal.cs new file mode 100644 index 0000000000..76b468e12e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal.cs @@ -0,0 +1,171 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics.X86; +using System.Runtime.Intrinsics; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static unsafe int Main(string[] args) + { + int testResult = Pass; + + if (Sse2.IsSupported) + { + if (Environment.Is64BitProcess) + { + { + long* inArray = stackalloc long[2]; + inArray[0] = 0xffffffff01l; + long* outBuffer = stackalloc long[2]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + + for (var i = 0; i < 2; i++) + { + if (inArray[i] != outBuffer[i]) + { + Console.WriteLine("Sse2 StoreNonTemporal failed on long:"); + for (var n = 0; n < 2; n++) + { + Console.Write(outBuffer[n] + ", "); + } + Console.WriteLine(); + + testResult = Fail; + break; + } + } + } + + { + ulong* inArray = stackalloc ulong[2]; + inArray[0] = 0xffffffffff01ul; + ulong* outBuffer = stackalloc ulong[2]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + + for (var i = 0; i < 2; i++) + { + if (inArray[i] != outBuffer[i]) + { + Console.WriteLine("Sse2 StoreNonTemporal failed on ulong:"); + for (var n = 0; n < 2; n++) + { + Console.Write(outBuffer[n] + ", "); + } + Console.WriteLine(); + + testResult = Fail; + break; + } + } + } + } + else + { + try + { + long* inArray = stackalloc long[2]; + inArray[0] = 0xffffffff01l; + long* outBuffer = stackalloc long[2]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.StoreNonTemporal)} failed on long: expected PlatformNotSupportedException exception."); + } + catch (PlatformNotSupportedException) + { + + } + catch(Exception ex) + { + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.StoreNonTemporal)}-{ex} failed on long: expected PlatformNotSupportedException exception."); + } + + try + { + ulong* inArray = stackalloc ulong[2]; + inArray[0] = 0xffffffffff01ul; + ulong* outBuffer = stackalloc ulong[2]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.StoreNonTemporal)} failed on ulong: expected PlatformNotSupportedException exception."); + } + catch (PlatformNotSupportedException) + { + + } + catch(Exception ex) + { + testResult = Fail; + Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.StoreNonTemporal)}-{ex} failed on ulong: expected PlatformNotSupportedException exception."); + } + } + + { + int* inArray = stackalloc int[4]; + inArray[0] = -784561; + int* outBuffer = stackalloc int[4]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + + for (var i = 0; i < 4; i++) + { + if (inArray[i] != outBuffer[i]) + { + Console.WriteLine("Sse2 StoreNonTemporal failed on int:"); + for (var n = 0; n < 4; n++) + { + Console.Write(outBuffer[n] + ", "); + } + Console.WriteLine(); + + testResult = Fail; + break; + } + } + } + + { + uint* inArray = stackalloc uint[4]; + inArray[0] = 0xffffff02u; + uint* outBuffer = stackalloc uint[4]; + + Sse2.StoreNonTemporal(outBuffer, inArray[0]); + + for (var i = 0; i < 4; i++) + { + if (inArray[i] != outBuffer[i]) + { + Console.WriteLine("Sse2 StoreNonTemporal failed on uint:"); + for (var n = 0; n < 4; n++) + { + Console.Write(outBuffer[n] + ", "); + } + Console.WriteLine(); + + testResult = Fail; + break; + } + } + } + } + + return testResult; + } + } +} + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_r.csproj new file mode 100644 index 0000000000..8ca2a261c6 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_r.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize></Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="StoreNonTemporal.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_ro.csproj new file mode 100644 index 0000000000..4f00c2b7c5 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/StoreNonTemporal_ro.csproj @@ -0,0 +1,34 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " /> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <PropertyGroup> + <DebugType>None</DebugType> + <Optimize>True</Optimize> + </PropertyGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <Compile Include="StoreNonTemporal.cs" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/TestTableSse2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/TestTableSse2.cs index ffba0a0613..23a63db28b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/TestTableSse2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/TestTableSse2.cs @@ -95,6 +95,7 @@ namespace IntelHardwareIntrinsicTest { private const int _stepSize = 16; private int _scalarStepSize; + private int _lengthInVectors; public static int ElementCount; private GCHandle _inHandle1; @@ -117,12 +118,27 @@ namespace IntelHardwareIntrinsicTest public Vector128<T> Vector1 => Unsafe.Read<Vector128<T>>((byte*)InArray1Ptr + (_index * _stepSize)); public Vector128<T> Vector2 => Unsafe.Read<Vector128<T>>((byte*)InArray2Ptr + (_index * _stepSize)); public Vector128<T> Vector3 => Unsafe.Read<Vector128<T>>((byte*)OutArrayPtr + (_index * _stepSize)); - public int Index { get => _index; set => _index = value; } + + public int Index + { + get => _index; + set + { + if (value < 0 || value >= _lengthInVectors) + { + throw new IndexOutOfRangeException(); + } + else + { + _index = value; + } + } + } public void SetOutArray(Vector128<T> value, int index = -1) { - index = index < 0 ? _index : index; - Unsafe.Write((byte*)OutArrayPtr + (index * _stepSize), value); + Index = index < 0 ? Index : index; + Unsafe.Write((byte*)OutArrayPtr + (Index * _stepSize), value); } public void SetOutArray(bool value1, Vector128<T> value2, int index = -1) @@ -164,6 +180,7 @@ namespace IntelHardwareIntrinsicTest public TestTableSse2(int lengthInVectors) { _scalarStepSize = Marshal.SizeOf<T>(); + _lengthInVectors = lengthInVectors; ElementCount = _stepSize / _scalarStepSize; int length = ElementCount * lengthInVectors; inArray1 = new T[length]; diff --git a/tests/src/Loader/regressions/GitHub_15544/main.cs b/tests/src/Loader/regressions/GitHub_15544/main.cs new file mode 100644 index 0000000000..25e7d79e41 --- /dev/null +++ b/tests/src/Loader/regressions/GitHub_15544/main.cs @@ -0,0 +1,37 @@ +// 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.IO; +using System.Reflection; + +public class CMain{ + public static int Main(String[] args) { + string tempFileName = Path.GetTempFileName(); + + bool isThrown = false; + + try + { + AssemblyName.GetAssemblyName(tempFileName); + } + catch (BadImageFormatException) + { + isThrown = true; + } + + File.Delete(tempFileName); + + if (isThrown) { + Console.WriteLine("PASS"); + + return 100; + } else { + Console.WriteLine("FAIL"); + + return 101; + } + } +} diff --git a/tests/src/Loader/regressions/GitHub_15544/main.csproj b/tests/src/Loader/regressions/GitHub_15544/main.csproj new file mode 100644 index 0000000000..e46a44ce52 --- /dev/null +++ b/tests/src/Loader/regressions/GitHub_15544/main.csproj @@ -0,0 +1,31 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{AC75380E-F196-4F32-9BCF-F0589AF864E6}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <Compile Include="main.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> +</Project> diff --git a/tests/src/Regressions/coreclr/15241/genericcontext.ilproj b/tests/src/Regressions/coreclr/15241/genericcontext.ilproj index ea2fd35bfc..40064db4a1 100644 --- a/tests/src/Regressions/coreclr/15241/genericcontext.ilproj +++ b/tests/src/Regressions/coreclr/15241/genericcontext.ilproj @@ -15,6 +15,9 @@ <OutputType>Exe</OutputType> <CLRTestKind>BuildAndRun</CLRTestKind> <CLRTestPriority>0</CLRTestPriority> + + <!-- Fails GCStress: https://github.com/dotnet/coreclr/issues/16898 --> + <GCStressIncompatible>true</GCStressIncompatible> </PropertyGroup> <ItemGroup> diff --git a/tests/src/Regressions/coreclr/GitHub_16833/Test16833.csproj b/tests/src/Regressions/coreclr/GitHub_16833/Test16833.csproj new file mode 100644 index 0000000000..10ccb29509 --- /dev/null +++ b/tests/src/Regressions/coreclr/GitHub_16833/Test16833.csproj @@ -0,0 +1,39 @@ +<?xml version="1.0" encoding="utf-8"?> +<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003"> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" /> + <PropertyGroup> + <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration> + <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform> + <SchemaVersion>2.0</SchemaVersion> + <ProjectGuid>{D1303490-9864-4CC7-9FC0-964B371C7D8C}</ProjectGuid> + <OutputType>Exe</OutputType> + <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids> + <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir> + <AllowUnsafeBlocks>true</AllowUnsafeBlocks> + <CLRTestKind>BuildAndRun</CLRTestKind> + <CLRTestPriority>1</CLRTestPriority> + </PropertyGroup> + <!-- Default configurations to help VS understand the configurations --> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "> + </PropertyGroup> + <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' "> + </PropertyGroup> + <ItemGroup> + <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies"> + <Visible>False</Visible> + </CodeAnalysisDependentAssemblyPaths> + </ItemGroup> + <ItemGroup> + <!-- Add Compile Object Here --> + <Compile Include="test16833.cs" /> + </ItemGroup> + <ItemGroup> + <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" /> + </ItemGroup> + <ItemGroup> + <ProjectReference Include="../../../Common/CoreCLRTestLibrary/CoreCLRTestLibrary.csproj" /> + </ItemGroup> + <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" /> + <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "> + </PropertyGroup> +</Project>
\ No newline at end of file diff --git a/tests/src/Regressions/coreclr/GitHub_16833/test16833.cs b/tests/src/Regressions/coreclr/GitHub_16833/test16833.cs new file mode 100644 index 0000000000..35e670b58a --- /dev/null +++ b/tests/src/Regressions/coreclr/GitHub_16833/test16833.cs @@ -0,0 +1,385 @@ +// 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; + +namespace TestShufflingThunk +{ + // This is a regression test for shuffling thunk creation on Unix AMD64. The calling convention causes some interesting shuffles that + // the code before the fix was not handling properly. + struct SLongLong + { + public long x; + public long y; + public override string ToString() + { + return $"[{x}, {y}]"; + } + } + + struct SIntDouble + { + public int x; + public double y; + public override string ToString() + { + return $"[{x}, {y}]"; + } + } + + struct SInt + { + public int x; + public override string ToString() + { + return $"[{x}]"; + } + } + + struct SLargeReturnStruct + { + public long x; + public long y; + public long z; + public string s; + public override string ToString() + { + return $"{s} -> [{x}, {y}, {z}]"; + } + } + + class TestClass + { + public static readonly string Test1Result = "Test1: 1, 2, 3, 4, [5, 6], 7"; + public static string Test1(int i1, int i2, int i3, int i4, SLongLong s, int i5) + { + return $"Test1: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + } + public static string Test2(int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5) + { + return $"Test2: {i1}, {i2}, {i3}, {i4}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}, {i5}"; + } + public static string Test3(int i1, int i2, int i3, int i4, int i5, SInt s, int i6) + { + return $"Test3: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {i6}"; + } + public static string Test4(int i1, int i2, int i3, int i4, SIntDouble s, double i5) + { + return $"Test4: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + } + public static string Test5(int i1, int i2, int i3, int i4, SLongLong s) + { + return $"Test5: {i1}, {i2}, {i3}, {i4}, {s}"; + } + public static string Test6(int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10) + { + return $"Test6: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}"; + } + + public static SLargeReturnStruct Test1RB(int i1, int i2, int i3, int i4, SLongLong s, int i5) + { + string args = $"Test1RB: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public static SLargeReturnStruct Test2RB(int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5) + { + string args = $"Test2RB: {i1}, {i2}, {i3}, {i4}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public static SLargeReturnStruct Test3RB(int i1, int i2, int i3, int i4, int i5, SInt s, int i6) + { + string args = $"Test3RB: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {i6}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public static SLargeReturnStruct Test4RB(int i1, int i2, int i3, int i4, SIntDouble s, double i5) + { + string args = $"Test4RB: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public static SLargeReturnStruct Test5RB(int i1, int i2, int i3, int i4, SLongLong s) + { + string args = $"Test5RB: {i1}, {i2}, {i3}, {i4}, {s}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public static SLargeReturnStruct Test6RB(int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10) + { + string args = $"Test6RB: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + + public string Test1M(int i1, int i2, int i3, int i4, SLongLong s, int i5) + { + return $"Test1M: i1, {i2}, {i3}, {i4}, {s}, {i5}"; + } + public string Test2M(int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5) + { + return $"Test2M: i1, {i2}, {i3}, {i4}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}, {i5}"; + } + public string Test3M(int i1, int i2, int i3, int i4, int i5, SInt s, int i6) + { + return $"Test3M: i1, {i2}, {i3}, {i4}, {i5}, {s}, {i6}"; + } + public string Test4M(int i1, int i2, int i3, int i4, SIntDouble s, double i5) + { + return $"Test4M: i1, {i2}, {i3}, {i4}, {s}, {i5}"; + } + public string Test5M(int i1, int i2, int i3, int i4, SLongLong s) + { + return $"Test5M: i1, {i2}, {i3}, {i4}, {s}"; + } + public string Test6M(int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10) + { + return $"Test6M: i1, {i2}, {i3}, {i4}, {i5}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}"; + } + public SLargeReturnStruct Test1MRB(int i1, int i2, int i3, int i4, SLongLong s, int i5) + { + string args = $"Test1MRB: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public SLargeReturnStruct Test2MRB(int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5) + { + string args = $"Test2MRB: {i1}, {i2}, {i3}, {i4}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public SLargeReturnStruct Test3MRB(int i1, int i2, int i3, int i4, int i5, SInt s, int i6) + { + string args = $"Test3MRB: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {i6}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public SLargeReturnStruct Test4MRB(int i1, int i2, int i3, int i4, SIntDouble s, double i5) + { + string args = $"Test4MRB: {i1}, {i2}, {i3}, {i4}, {s}, {i5}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public SLargeReturnStruct Test5MRB(int i1, int i2, int i3, int i4, SLongLong s) + { + string args = $"Test5MRB: {i1}, {i2}, {i3}, {i4}, {s}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + public SLargeReturnStruct Test6MRB(int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10) + { + string args = $"Test6MRB: {i1}, {i2}, {i3}, {i4}, {i5}, {s}, {f1}, {f2}, {f3}, {f4}, {f5}, {f6}, {f7}, {f8}, {f9}, {f10}"; + return new SLargeReturnStruct { x = -1, y = -2, z = -3, s = args }; + } + } + + class Test16833 + { + delegate string Delegate2m(TestClass tc, int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5); + delegate string Delegate6m(TestClass tc, int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10); + delegate SLargeReturnStruct Delegate2mrb(TestClass tc, int i1, int i2, int i3, int i4, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10, int i5); + delegate SLargeReturnStruct Delegate6mrb(TestClass tc, int i1, int i2, int i3, int i4, int i5, SIntDouble s, double f1, double f2, double f3, double f4, double f5, double f6, double f7, double f8, double f9, double f10); + + static void CheckResult(ref int exitCode, string test, string result, string expected) + { + if (result != expected) + { + Console.WriteLine($"Test {test} failed. Expected \"{expected}\", got \"{result}\""); + exitCode = 1; + } + } + + static int Main(string[] args) + { + int exitCode = 100; + + string result; + + var func1 = (Func<int, int, int, int, SLongLong, int, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SLongLong, int, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test1))); + + SLongLong s1 = new SLongLong { x = 5, y = 6}; + result = func1(1, 2, 3, 4, s1, 7); + CheckResult(ref exitCode, nameof(TestClass.Test1), result, "Test1: 1, 2, 3, 4, [5, 6], 7"); + + var func2 = (Func<int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, int, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, int, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test2))); + + SIntDouble s2 = new SIntDouble { x = 5, y = 6.0 }; + result = func2(1, 2, 3, 4, s2, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17); + CheckResult(ref exitCode, nameof(TestClass.Test2), result, "Test2: 1, 2, 3, 4, [5, 6], 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17"); + + var func3 = (Func<int, int, int, int, int, SInt, int, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, int, SInt, int, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test3))); + + SInt s3 = new SInt { x = 6 }; + result = func3(1, 2, 3, 4, 5, s3, 7); + CheckResult(ref exitCode, nameof(TestClass.Test3), result, "Test3: 1, 2, 3, 4, 5, [6], 7"); + + var func4 = (Func<int, int, int, int, SIntDouble, double, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SIntDouble, double, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test4))); + + SIntDouble s4 = new SIntDouble { x = 5, y = 6.0 }; + result = func4(1, 2, 3, 4, s4, 7.0); + CheckResult(ref exitCode, nameof(TestClass.Test4), result, "Test4: 1, 2, 3, 4, [5, 6], 7"); + + var func5 = (Func<int, int, int, int, SLongLong, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SLongLong, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test5))); + + SLongLong s5 = new SLongLong { x = 5, y = 6 }; + result = func5(1, 2, 3, 4, s1); + CheckResult(ref exitCode, nameof(TestClass.Test5), result, "Test5: 1, 2, 3, 4, [5, 6]"); + + var func6 = (Func<int, int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, string>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, string>), + typeof(TestClass).GetMethod(nameof(TestClass.Test6))); + + SIntDouble s6 = new SIntDouble { x = 6, y = 7.0 }; + result = func6(1, 2, 3, 4, 5, s6, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0); + CheckResult(ref exitCode, nameof(TestClass.Test6), result, "Test6: 1, 2, 3, 4, 5, [6, 7], 8, 9, 10, 11, 12, 13, 14, 15, 16, 17"); + + TestClass tc = new TestClass(); + + var func1m = (Func<TestClass, int, int, int, int, SLongLong, int, string>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SLongLong, int, string>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test1M))); + + result = func1m(tc, 1, 2, 3, 4, s1, 7); + CheckResult(ref exitCode, nameof(TestClass.Test1M), result, "Test1M: i1, 2, 3, 4, [5, 6], 7"); + + var func2m = (Delegate2m)Delegate.CreateDelegate( + typeof(Delegate2m), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test2M))); + + result = func2m(tc, 1, 2, 3, 4, s2, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17); + CheckResult(ref exitCode, nameof(TestClass.Test2M), result, "Test2M: i1, 2, 3, 4, [5, 6], 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17"); + + var func3m = (Func<TestClass, int, int, int, int, int, SInt, int, string>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, int, SInt, int, string>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test3M))); + + result = func3m(tc, 1, 2, 3, 4, 5, s3, 7); + CheckResult(ref exitCode, nameof(TestClass.Test3M), result, "Test3M: i1, 2, 3, 4, 5, [6], 7"); + + var func4m = (Func<TestClass, int, int, int, int, SIntDouble, double, string>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SIntDouble, double, string>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test4M))); + + result = func4m(tc, 1, 2, 3, 4, s4, 7.0); + CheckResult(ref exitCode, nameof(TestClass.Test4M), result, "Test4M: i1, 2, 3, 4, [5, 6], 7"); + + var func5m = (Func<TestClass, int, int, int, int, SLongLong, string>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SLongLong, string>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test5M))); + + result = func5m(tc, 1, 2, 3, 4, s1); + CheckResult(ref exitCode, nameof(TestClass.Test5M), result, "Test5M: i1, 2, 3, 4, [5, 6]"); + + var func6m = (Delegate6m)Delegate.CreateDelegate( + typeof(Delegate6m), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test6M))); + + result = func6m(tc, 1, 2, 3, 4, 5, s6, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0); + CheckResult(ref exitCode, nameof(TestClass.Test6M), result, "Test6M: i1, 2, 3, 4, 5, [6, 7], 8, 9, 10, 11, 12, 13, 14, 15, 16, 17"); + + var func1rb = (Func<int, int, int, int, SLongLong, int, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SLongLong, int, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test1RB))); + + + SLargeReturnStruct result1 = func1rb(1, 2, 3, 4, s1, 7); + CheckResult(ref exitCode, nameof(TestClass.Test1RB), result1.ToString(), "Test1RB: 1, 2, 3, 4, [5, 6], 7 -> [-1, -2, -3]"); + + var func2rb = (Func<int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, int, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, int, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test2RB))); + + SLargeReturnStruct result2 = func2rb(1, 2, 3, 4, s2, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17); + CheckResult(ref exitCode, nameof(TestClass.Test2RB), result2.ToString(), "Test2RB: 1, 2, 3, 4, [5, 6], 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> [-1, -2, -3]"); + + var func3rb = (Func<int, int, int, int, int, SInt, int, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, int, SInt, int, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test3RB))); + + SLargeReturnStruct result3 = func3rb(1, 2, 3, 4, 5, s3, 7); + CheckResult(ref exitCode, nameof(TestClass.Test3RB), result3.ToString(), "Test3RB: 1, 2, 3, 4, 5, [6], 7 -> [-1, -2, -3]"); + + var func4rb = (Func<int, int, int, int, SIntDouble, double, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SIntDouble, double, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test4RB))); + + SLargeReturnStruct result4 = func4rb(1, 2, 3, 4, s4, 7.0); + CheckResult(ref exitCode, nameof(TestClass.Test4RB), result4.ToString(), "Test4RB: 1, 2, 3, 4, [5, 6], 7 -> [-1, -2, -3]"); + + var func5rb = (Func<int, int, int, int, SLongLong, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, SLongLong, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test5RB))); + + SLargeReturnStruct result5 = func5rb(1, 2, 3, 4, s1); + CheckResult(ref exitCode, nameof(TestClass.Test5RB), result5.ToString(), "Test5RB: 1, 2, 3, 4, [5, 6] -> [-1, -2, -3]"); + + var func6rb = (Func<int, int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<int, int, int, int, int, SIntDouble, double, double, double, double, double, double, double, double, double, double, SLargeReturnStruct>), + typeof(TestClass).GetMethod(nameof(TestClass.Test6RB))); + + SLargeReturnStruct result6 = func6rb(1, 2, 3, 4, 5, s6, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0); + CheckResult(ref exitCode, nameof(TestClass.Test6RB), result6.ToString(), "Test6RB: 1, 2, 3, 4, 5, [6, 7], 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> [-1, -2, -3]"); + + var func1mrb = (Func<TestClass, int, int, int, int, SLongLong, int, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SLongLong, int, SLargeReturnStruct>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test1MRB))); + + SLargeReturnStruct result1mrb = func1mrb(tc, 1, 2, 3, 4, s1, 7); + CheckResult(ref exitCode, nameof(TestClass.Test1MRB), result1mrb.ToString(), "Test1MRB: 1, 2, 3, 4, [5, 6], 7 -> [-1, -2, -3]"); + + var func2mrb = (Delegate2mrb)Delegate.CreateDelegate( + typeof(Delegate2mrb), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test2MRB))); + + SLargeReturnStruct result2mrb = func2mrb(tc, 1, 2, 3, 4, s2, 7.0, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17); + CheckResult(ref exitCode, nameof(TestClass.Test2MRB), result2mrb.ToString(), "Test2MRB: 1, 2, 3, 4, [5, 6], 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> [-1, -2, -3]"); + + var func3mrb = (Func<TestClass, int, int, int, int, int, SInt, int, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, int, SInt, int, SLargeReturnStruct>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test3MRB))); + + SLargeReturnStruct result3mrb = func3mrb(tc, 1, 2, 3, 4, 5, s3, 7); + CheckResult(ref exitCode, nameof(TestClass.Test3MRB), result3mrb.ToString(), "Test3MRB: 1, 2, 3, 4, 5, [6], 7 -> [-1, -2, -3]"); + + var func4mrb = (Func<TestClass, int, int, int, int, SIntDouble, double, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SIntDouble, double, SLargeReturnStruct>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test4MRB))); + + SLargeReturnStruct result4mrb = func4mrb(tc, 1, 2, 3, 4, s4, 7.0); + CheckResult(ref exitCode, nameof(TestClass.Test4MRB), result4mrb.ToString(), "Test4MRB: 1, 2, 3, 4, [5, 6], 7 -> [-1, -2, -3]"); + + var func5mrb = (Func<TestClass, int, int, int, int, SLongLong, SLargeReturnStruct>)Delegate.CreateDelegate( + typeof(Func<TestClass, int, int, int, int, SLongLong, SLargeReturnStruct>), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test5MRB))); + + SLargeReturnStruct result5mrb = func5mrb(tc, 1, 2, 3, 4, s1); + CheckResult(ref exitCode, nameof(TestClass.Test5MRB), result5mrb.ToString(), "Test5MRB: 1, 2, 3, 4, [5, 6] -> [-1, -2, -3]"); + + var func6mrb = (Delegate6mrb)Delegate.CreateDelegate( + typeof(Delegate6mrb), + null, + typeof(TestClass).GetMethod(nameof(TestClass.Test6MRB))); + + SLargeReturnStruct result6mrb = func6mrb(tc, 1, 2, 3, 4, 5, s6, 8.0, 9.0, 10.0, 11.0, 12.0, 13.0, 14.0, 15.0, 16.0, 17.0); + CheckResult(ref exitCode, nameof(TestClass.Test6MRB), result6mrb.ToString(), "Test6MRB: 1, 2, 3, 4, 5, [6, 7], 8, 9, 10, 11, 12, 13, 14, 15, 16, 17 -> [-1, -2, -3]"); + + if (exitCode == 100) + { + Console.WriteLine("Test SUCCEEDED"); + } + + return exitCode; + } + } +} |