diff options
author | Fei Peng <fei.peng@intel.com> | 2018-03-02 16:34:03 -0800 |
---|---|---|
committer | Tanner Gooding <tagoo@outlook.com> | 2018-03-03 07:11:59 -0800 |
commit | d44ff6450feafb5b7355c243b604c14434c04d09 (patch) | |
tree | f6e694e2980ee8ec4f8ab26dfe5047f6b160fefe /tests/src/JIT | |
parent | f5a424896f0e81e2459908957742201bf1074f10 (diff) | |
download | coreclr-d44ff6450feafb5b7355c243b604c14434c04d09.tar.gz coreclr-d44ff6450feafb5b7355c243b604c14434c04d09.tar.bz2 coreclr-d44ff6450feafb5b7355c243b604c14434c04d09.zip |
Implement AVX/AVX BroadcastScalarToVector*
Diffstat (limited to 'tests/src/JIT')
31 files changed, 6897 insertions, 3 deletions
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128.cs new file mode 100644 index 0000000000..b755576180 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128.cs @@ -0,0 +1,84 @@ +// 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 (Avx.IsSupported) + { + using (TestTable<float> floatTable = new TestTable<float>(new float[8] { 1, -5, 100, 0, 1, 2, 3, 4 }, new float[4])) + { + var vf = Avx.BroadcastScalarToVector128((float*)(floatTable.inArrayPtr)); + Unsafe.Write(floatTable.outArrayPtr, vf); + + if (!floatTable.CheckResult((x, y) => BitConverter.SingleToInt32Bits(x) == BitConverter.SingleToInt32Bits(y))) + { + Console.WriteLine("AVX BroadcastScalarToVector128 failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray; + public T[] outArray; + + public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle; + GCHandle outHandle; + public TestTable(T[] a, T[] b) + { + this.inArray = a; + this.outArray = b; + + inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func<T, T, bool> check) + { + for (int i = 0; i < outArray.Length; i++) + { + if (!check(inArray[0], outArray[i])) + { + return false; + } + } + return true; + } + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128_r.csproj new file mode 100644 index 0000000000..4c6af4196e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128_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="BroadcastScalarToVector128.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/Avx/BroadcastScalarToVector128_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128_ro.csproj new file mode 100644 index 0000000000..ea07bab4c9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector128_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="BroadcastScalarToVector128.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/Avx/BroadcastScalarToVector256.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256.cs new file mode 100644 index 0000000000..cbb5a079a2 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256.cs @@ -0,0 +1,100 @@ +// 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 (Avx.IsSupported) + { + using (TestTable<float> floatTable = new TestTable<float>(new float[8] { 1, -5, 100, 0, 1, 2, 3, 4 }, new float[8])) + { + var vf = Avx.BroadcastScalarToVector256((float*)(floatTable.inArrayPtr)); + Unsafe.Write(floatTable.outArrayPtr, vf); + + if (!floatTable.CheckResult((x, y) => BitConverter.SingleToInt32Bits(x) == BitConverter.SingleToInt32Bits(y))) + { + Console.WriteLine("AVX BroadcastScalarToVector256 failed on float:"); + foreach (var item in floatTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + + using (TestTable<double> doubleTable = new TestTable<double>(new double[4] { 1, -5, 100, 0}, new double[4])) + { + var vf = Avx.BroadcastScalarToVector256((double*)(doubleTable.inArrayPtr)); + Unsafe.Write(doubleTable.outArrayPtr, vf); + + if (!doubleTable.CheckResult((x, y) => BitConverter.DoubleToInt64Bits(x) == BitConverter.DoubleToInt64Bits(y))) + { + Console.WriteLine("AVX BroadcastScalarToVector256 failed on double:"); + foreach (var item in doubleTable.outArray) + { + Console.Write(item + ", "); + } + Console.WriteLine(); + testResult = Fail; + } + } + } + return testResult; + } + + public unsafe struct TestTable<T> : IDisposable where T : struct + { + public T[] inArray; + public T[] outArray; + + public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer(); + public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer(); + + GCHandle inHandle; + GCHandle outHandle; + public TestTable(T[] a, T[] b) + { + this.inArray = a; + this.outArray = b; + + inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned); + outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned); + } + public bool CheckResult(Func<T, T, bool> check) + { + for (int i = 0; i < outArray.Length; i++) + { + if (!check(inArray[0], outArray[i])) + { + return false; + } + } + return true; + } + + public void Dispose() + { + inHandle.Free(); + outHandle.Free(); + } + } + + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256_r.csproj new file mode 100644 index 0000000000..86b28ad53b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256_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="BroadcastScalarToVector256.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/Avx/BroadcastScalarToVector256_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256_ro.csproj new file mode 100644 index 0000000000..a6fc2c671f --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx/BroadcastScalarToVector256_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="BroadcastScalarToVector256.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/Avx2/Avx2_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj index 178f5cd65e..3555431351 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj @@ -54,7 +54,27 @@ <Compile Include="Average.Byte.cs" /> <Compile Include="Average.UInt16.cs" /> <Compile Include="BlendVariable.Byte.cs" /> - <Compile Include="BlendVariable.SByte.cs" /> + <Compile Include="BlendVariable.SByte.cs" /> + <Compile Include="BroadcastScalarToVector128.Byte.cs" /> + <Compile Include="BroadcastScalarToVector128.SByte.cs" /> + <Compile Include="BroadcastScalarToVector128.Int16.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt16.cs" /> + <Compile Include="BroadcastScalarToVector128.Int32.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt32.cs" /> + <Compile Include="BroadcastScalarToVector128.Int64.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt64.cs" /> + <Compile Include="BroadcastScalarToVector128.Single.cs" /> + <Compile Include="BroadcastScalarToVector128.Double.cs" /> + <Compile Include="BroadcastScalarToVector256.Byte.cs" /> + <Compile Include="BroadcastScalarToVector256.SByte.cs" /> + <Compile Include="BroadcastScalarToVector256.Int16.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt16.cs" /> + <Compile Include="BroadcastScalarToVector256.Int32.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt32.cs" /> + <Compile Include="BroadcastScalarToVector256.Int64.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt64.cs" /> + <Compile Include="BroadcastScalarToVector256.Single.cs" /> + <Compile Include="BroadcastScalarToVector256.Double.cs" /> <Compile Include="CompareEqual.Byte.cs" /> <Compile Include="CompareEqual.Int16.cs" /> <Compile Include="CompareEqual.Int32.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj index c928b08268..5570c82acc 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj @@ -54,7 +54,27 @@ <Compile Include="Average.Byte.cs" /> <Compile Include="Average.UInt16.cs" /> <Compile Include="BlendVariable.Byte.cs" /> - <Compile Include="BlendVariable.SByte.cs" /> + <Compile Include="BlendVariable.SByte.cs" /> + <Compile Include="BroadcastScalarToVector128.Byte.cs" /> + <Compile Include="BroadcastScalarToVector128.SByte.cs" /> + <Compile Include="BroadcastScalarToVector128.Int16.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt16.cs" /> + <Compile Include="BroadcastScalarToVector128.Int32.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt32.cs" /> + <Compile Include="BroadcastScalarToVector128.Int64.cs" /> + <Compile Include="BroadcastScalarToVector128.UInt64.cs" /> + <Compile Include="BroadcastScalarToVector128.Single.cs" /> + <Compile Include="BroadcastScalarToVector128.Double.cs" /> + <Compile Include="BroadcastScalarToVector256.Byte.cs" /> + <Compile Include="BroadcastScalarToVector256.SByte.cs" /> + <Compile Include="BroadcastScalarToVector256.Int16.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt16.cs" /> + <Compile Include="BroadcastScalarToVector256.Int32.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt32.cs" /> + <Compile Include="BroadcastScalarToVector256.Int64.cs" /> + <Compile Include="BroadcastScalarToVector256.UInt64.cs" /> + <Compile Include="BroadcastScalarToVector256.Single.cs" /> + <Compile Include="BroadcastScalarToVector256.Double.cs" /> <Compile Include="CompareEqual.Byte.cs" /> <Compile Include="CompareEqual.Int16.cs" /> <Compile Include="CompareEqual.Int32.cs" /> diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Byte.cs new file mode 100644 index 0000000000..6d62c44d1b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Byte.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Byte() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Byte(); + + 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__BroadcastScalarToVector128Byte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128<Byte> _clsVar; + + private Vector128<Byte> _fld; + + private SimpleUnaryOpTest__DataTable<Byte, Byte> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar), ref Unsafe.As<Byte, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128Byte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld), ref Unsafe.As<Byte, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Byte, Byte>(_data, new Byte[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Byte>( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Byte>( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Byte>( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Byte>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Byte(); + var result = Avx2.BroadcastScalarToVector128<Byte>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Byte>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Byte>(Vector128<Byte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Double.cs new file mode 100644 index 0000000000..b1b5169835 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Double.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Double() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Double(); + + 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__BroadcastScalarToVector128Double + { + 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__BroadcastScalarToVector128Double() + { + 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__BroadcastScalarToVector128Double() + { + 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 => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Double>( + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Double>( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Double>( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Double>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Double(); + var result = Avx2.BroadcastScalarToVector128<Double>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Double>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<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(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Double>(Vector128<Double>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int16.cs new file mode 100644 index 0000000000..ac47ab40e1 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int16.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Int16() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int16(); + + 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__BroadcastScalarToVector128Int16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128<Int16> _clsVar; + + private Vector128<Int16> _fld; + + private SimpleUnaryOpTest__DataTable<Int16, Int16> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128Int16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar), ref Unsafe.As<Int16, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128Int16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld), ref Unsafe.As<Int16, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int16, Int16>(_data, new Int16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Int16>( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Int16>( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Int16>( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int16>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int16(); + var result = Avx2.BroadcastScalarToVector128<Int16>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int16>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Int16>(Vector128<Int16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int32.cs new file mode 100644 index 0000000000..68fa2d97fd --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int32.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Int32() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int32(); + + 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__BroadcastScalarToVector128Int32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128<Int32> _clsVar; + + private Vector128<Int32> _fld; + + private SimpleUnaryOpTest__DataTable<Int32, Int32> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128Int32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar), ref Unsafe.As<Int32, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128Int32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld), ref Unsafe.As<Int32, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int32, Int32>(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Int32>( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Int32>( + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Int32>( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int32>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int32(); + var result = Avx2.BroadcastScalarToVector128<Int32>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int32>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Int32>(Vector128<Int32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int64.cs new file mode 100644 index 0000000000..ee9b10a77c --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Int64.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Int64() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int64(); + + 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__BroadcastScalarToVector128Int64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128<Int64> _clsVar; + + private Vector128<Int64> _fld; + + private SimpleUnaryOpTest__DataTable<Int64, Int64> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128Int64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar), ref Unsafe.As<Int64, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128Int64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld), ref Unsafe.As<Int64, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int64, Int64>(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Int64>( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Int64>( + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Int64>( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int64>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Int64(); + var result = Avx2.BroadcastScalarToVector128<Int64>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Int64>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Int64>(Vector128<Int64>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.SByte.cs new file mode 100644 index 0000000000..057189618e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.SByte.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128SByte() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128SByte(); + + 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__BroadcastScalarToVector128SByte + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128<SByte> _clsVar; + + private Vector128<SByte> _fld; + + private SimpleUnaryOpTest__DataTable<SByte, SByte> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128SByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar), ref Unsafe.As<SByte, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128SByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld), ref Unsafe.As<SByte, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<SByte, SByte>(_data, new SByte[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<SByte>( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<SByte>( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<SByte>( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<SByte>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128SByte(); + var result = Avx2.BroadcastScalarToVector128<SByte>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<SByte>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<SByte>(Vector128<SByte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Single.cs new file mode 100644 index 0000000000..32550faa74 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.Single.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128Single() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Single(); + + 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__BroadcastScalarToVector128Single + { + 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__BroadcastScalarToVector128Single() + { + 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__BroadcastScalarToVector128Single() + { + 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 => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<Single>( + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<Single>( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<Single>( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<Single>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128Single(); + var result = Avx2.BroadcastScalarToVector128<Single>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<Single>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<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(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<Single>(Vector128<Single>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt16.cs new file mode 100644 index 0000000000..dc7c04409e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt16.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128UInt16() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt16(); + + 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__BroadcastScalarToVector128UInt16 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128<UInt16> _clsVar; + + private Vector128<UInt16> _fld; + + private SimpleUnaryOpTest__DataTable<UInt16, UInt16> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar), ref Unsafe.As<UInt16, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128UInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld), ref Unsafe.As<UInt16, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt16, UInt16>(_data, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<UInt16>( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<UInt16>( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<UInt16>( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt16>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt16(); + var result = Avx2.BroadcastScalarToVector128<UInt16>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt16>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<UInt16>(Vector128<UInt16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt32.cs new file mode 100644 index 0000000000..5f5815d6ae --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt32.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128UInt32() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt32(); + + 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__BroadcastScalarToVector128UInt32 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int RetElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128<UInt32> _clsVar; + + private Vector128<UInt32> _fld; + + private SimpleUnaryOpTest__DataTable<UInt32, UInt32> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128UInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar), ref Unsafe.As<UInt32, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128UInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld), ref Unsafe.As<UInt32, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt32, UInt32>(_data, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<UInt32>( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<UInt32>( + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<UInt32>( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt32>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt32(); + var result = Avx2.BroadcastScalarToVector128<UInt32>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt32>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<UInt32>(Vector128<UInt32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt64.cs new file mode 100644 index 0000000000..59e8914738 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector128.UInt64.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector128UInt64() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt64(); + + 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__BroadcastScalarToVector128UInt64 + { + private const int VectorSize = 16; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int RetElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128<UInt64> _clsVar; + + private Vector128<UInt64> _fld; + + private SimpleUnaryOpTest__DataTable<UInt64, UInt64> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector128UInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar), ref Unsafe.As<UInt64, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector128UInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld), ref Unsafe.As<UInt64, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt64, UInt64>(_data, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector128<UInt64>( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector128<UInt64>( + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector128<UInt64>( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector128)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt64>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector128<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector128<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector128UInt64(); + var result = Avx2.BroadcastScalarToVector128<UInt64>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector128<UInt64>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector128)}<UInt64>(Vector128<UInt64>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Byte.cs new file mode 100644 index 0000000000..18ae07f47a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Byte.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Byte() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Byte(); + + 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__BroadcastScalarToVector256Byte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Byte); + private const int RetElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data = new Byte[Op1ElementCount]; + + private static Vector128<Byte> _clsVar; + + private Vector128<Byte> _fld; + + private SimpleUnaryOpTest__DataTable<Byte, Byte> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Byte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar), ref Unsafe.As<Byte, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256Byte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld), ref Unsafe.As<Byte, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Byte, Byte>(_data, new Byte[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Byte>( + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Byte>( + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Byte>( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Byte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Byte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Byte>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Byte>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Byte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Byte(); + var result = Avx2.BroadcastScalarToVector256<Byte>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Byte>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Byte> firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray = new Byte[Op1ElementCount]; + Byte[] outArray = new Byte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Byte[] firstOp, Byte[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Byte>(Vector128<Byte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Double.cs new file mode 100644 index 0000000000..64bedc42af --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Double.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Double() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Double(); + + 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__BroadcastScalarToVector256Double + { + 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 Vector128<Double> _clsVar; + + private Vector128<Double> _fld; + + private SimpleUnaryOpTest__DataTable<Double, Double> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Double() + { + 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__BroadcastScalarToVector256Double() + { + 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 => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Double>( + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Double>( + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Double>( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Double) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Double>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Double>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Double>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Double>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Double(); + var result = Avx2.BroadcastScalarToVector256<Double>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Double>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<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(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Double>(Vector128<Double>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int16.cs new file mode 100644 index 0000000000..89e15181e3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int16.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Int16() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int16(); + + 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__BroadcastScalarToVector256Int16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Int16); + private const int RetElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data = new Int16[Op1ElementCount]; + + private static Vector128<Int16> _clsVar; + + private Vector128<Int16> _fld; + + private SimpleUnaryOpTest__DataTable<Int16, Int16> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Int16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar), ref Unsafe.As<Int16, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256Int16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld), ref Unsafe.As<Int16, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (short)(random.Next(0, short.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int16, Int16>(_data, new Int16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Int16>( + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Int16>( + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Int16>( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int16) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int16>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int16(); + var result = Avx2.BroadcastScalarToVector256<Int16>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int16>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int16> firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray = new Int16[Op1ElementCount]; + Int16[] outArray = new Int16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int16[] firstOp, Int16[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Int16>(Vector128<Int16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int32.cs new file mode 100644 index 0000000000..e33cb6cd6b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int32.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Int32() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int32(); + + 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__BroadcastScalarToVector256Int32 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Int32); + private const int RetElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data = new Int32[Op1ElementCount]; + + private static Vector128<Int32> _clsVar; + + private Vector128<Int32> _fld; + + private SimpleUnaryOpTest__DataTable<Int32, Int32> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Int32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar), ref Unsafe.As<Int32, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256Int32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld), ref Unsafe.As<Int32, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (int)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int32, Int32>(_data, new Int32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Int32>( + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Int32>( + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Int32>( + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int32) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int32>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int32(); + var result = Avx2.BroadcastScalarToVector256<Int32>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int32>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int32> firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int32[] inArray = new Int32[Op1ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int32[] firstOp, Int32[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Int32>(Vector128<Int32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int64.cs new file mode 100644 index 0000000000..bd812ce42d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Int64.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Int64() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int64(); + + 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__BroadcastScalarToVector256Int64 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(Int64); + private const int RetElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data = new Int64[Op1ElementCount]; + + private static Vector128<Int64> _clsVar; + + private Vector128<Int64> _fld; + + private SimpleUnaryOpTest__DataTable<Int64, Int64> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Int64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar), ref Unsafe.As<Int64, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256Int64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld), ref Unsafe.As<Int64, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (long)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<Int64, Int64>(_data, new Int64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Int64>( + Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Int64>( + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Int64>( + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Int64) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Int64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int64>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Int64>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Int64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Int64(); + var result = Avx2.BroadcastScalarToVector256<Int64>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Int64>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<Int64> firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + Int64[] inArray = new Int64[Op1ElementCount]; + Int64[] outArray = new Int64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(Int64[] firstOp, Int64[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Int64>(Vector128<Int64>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.SByte.cs new file mode 100644 index 0000000000..67438a34a1 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.SByte.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256SByte() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256SByte(); + + 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__BroadcastScalarToVector256SByte + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(SByte); + private const int RetElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data = new SByte[Op1ElementCount]; + + private static Vector128<SByte> _clsVar; + + private Vector128<SByte> _fld; + + private SimpleUnaryOpTest__DataTable<SByte, SByte> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256SByte() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar), ref Unsafe.As<SByte, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256SByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld), ref Unsafe.As<SByte, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (sbyte)(random.Next(0, sbyte.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<SByte, SByte>(_data, new SByte[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<SByte>( + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<SByte>( + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<SByte>( + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(SByte) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<SByte>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<SByte>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<SByte>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((SByte*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<SByte>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256SByte(); + var result = Avx2.BroadcastScalarToVector256<SByte>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<SByte>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<SByte> firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + SByte[] inArray = new SByte[Op1ElementCount]; + SByte[] outArray = new SByte[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<SByte, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(SByte[] firstOp, SByte[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<SByte>(Vector128<SByte>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Single.cs new file mode 100644 index 0000000000..3520940d03 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.Single.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256Single() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Single(); + + 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__BroadcastScalarToVector256Single + { + 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 Vector128<Single> _clsVar; + + private Vector128<Single> _fld; + + private SimpleUnaryOpTest__DataTable<Single, Single> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256Single() + { + 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__BroadcastScalarToVector256Single() + { + 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 => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<Single>( + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<Single>( + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<Single>( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(Single) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<Single>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<Single>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<Single>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse.LoadVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse.LoadAlignedVector128((Single*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<Single>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256Single(); + var result = Avx2.BroadcastScalarToVector256<Single>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<Single>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<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(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[i]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<Single>(Vector128<Single>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt16.cs new file mode 100644 index 0000000000..9612f9b945 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt16.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256UInt16() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt16(); + + 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__BroadcastScalarToVector256UInt16 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(UInt16); + private const int RetElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data = new UInt16[Op1ElementCount]; + + private static Vector128<UInt16> _clsVar; + + private Vector128<UInt16> _fld; + + private SimpleUnaryOpTest__DataTable<UInt16, UInt16> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256UInt16() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar), ref Unsafe.As<UInt16, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256UInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld), ref Unsafe.As<UInt16, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt16, UInt16>(_data, new UInt16[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<UInt16>( + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<UInt16>( + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<UInt16>( + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt16) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt16>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt16>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt16>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt16(); + var result = Avx2.BroadcastScalarToVector256<UInt16>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt16>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt16> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt16[] inArray = new UInt16[Op1ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt16[] firstOp, UInt16[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<UInt16>(Vector128<UInt16>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt32.cs new file mode 100644 index 0000000000..32a6bff3b7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt32.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256UInt32() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt32(); + + 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__BroadcastScalarToVector256UInt32 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(UInt32); + private const int RetElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data = new UInt32[Op1ElementCount]; + + private static Vector128<UInt32> _clsVar; + + private Vector128<UInt32> _fld; + + private SimpleUnaryOpTest__DataTable<UInt32, UInt32> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256UInt32() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar), ref Unsafe.As<UInt32, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256UInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld), ref Unsafe.As<UInt32, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt32, UInt32>(_data, new UInt32[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<UInt32>( + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<UInt32>( + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<UInt32>( + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt32) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt32>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt32>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt32>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt32(); + var result = Avx2.BroadcastScalarToVector256<UInt32>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt32>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt32> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt32[] inArray = new UInt32[Op1ElementCount]; + UInt32[] outArray = new UInt32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt32[] firstOp, UInt32[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<UInt32>(Vector128<UInt32>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt64.cs new file mode 100644 index 0000000000..0bcac6ea98 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/BroadcastScalarToVector256.UInt64.cs @@ -0,0 +1,309 @@ +// 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 BroadcastScalarToVector256UInt64() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt64(); + + 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__BroadcastScalarToVector256UInt64 + { + private const int VectorSize = 32; + + private const int Op1ElementCount = VectorSize / sizeof(UInt64); + private const int RetElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data = new UInt64[Op1ElementCount]; + + private static Vector128<UInt64> _clsVar; + + private Vector128<UInt64> _fld; + + private SimpleUnaryOpTest__DataTable<UInt64, UInt64> _dataTable; + + static SimpleUnaryOpTest__BroadcastScalarToVector256UInt64() + { + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar), ref Unsafe.As<UInt64, byte>(ref _data[0]), VectorSize); + } + + public SimpleUnaryOpTest__BroadcastScalarToVector256UInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld), ref Unsafe.As<UInt64, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) { _data[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleUnaryOpTest__DataTable<UInt64, UInt64>(_data, new UInt64[RetElementCount], VectorSize); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + var result = Avx2.BroadcastScalarToVector256<UInt64>( + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + var result = Avx2.BroadcastScalarToVector256<UInt64>( + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + var result = Avx2.BroadcastScalarToVector256<UInt64>( + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.BroadcastScalarToVector256)) + .MakeGenericMethod( new Type[] { typeof(UInt64) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256<UInt64>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt64>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + var firstOp = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArrayPtr); + var result = Avx2.BroadcastScalarToVector256<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + var firstOp = Sse2.LoadVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + var firstOp = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArrayPtr)); + var result = Avx2.BroadcastScalarToVector256<UInt64>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + } + + public void RunLclFldScenario() + { + var test = new SimpleUnaryOpTest__BroadcastScalarToVector256UInt64(); + var result = Avx2.BroadcastScalarToVector256<UInt64>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + } + + public void RunFldScenario() + { + var result = Avx2.BroadcastScalarToVector256<UInt64>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128<UInt64> firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + { + UInt64[] inArray = new UInt64[Op1ElementCount]; + UInt64[] outArray = new UInt64[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + } + + private void ValidateResult(UInt64[] firstOp, UInt64[] result, [CallerMemberName] string method = "") + { + if (firstOp[0] != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if ((firstOp[0] != result[i])) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.BroadcastScalarToVector256)}<UInt64>(Vector128<UInt64>): {method} failed:"); + Console.WriteLine($" firstOp: ({string.Join(", ", firstOp)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs index c89da0a534..bc12228824 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs @@ -40,6 +40,26 @@ namespace JIT.HardwareIntrinsics.X86 ["Average.UInt16"] = AverageUInt16, ["BlendVariable.Byte"] = BlendVariableByte, ["BlendVariable.SByte"] = BlendVariableSByte, + ["BroadcastScalarToVector128.Byte"] = BroadcastScalarToVector128Byte, + ["BroadcastScalarToVector128.SByte"] = BroadcastScalarToVector128SByte, + ["BroadcastScalarToVector128.Int16"] = BroadcastScalarToVector128Int16, + ["BroadcastScalarToVector128.UInt16"] = BroadcastScalarToVector128UInt16, + ["BroadcastScalarToVector128.Int32"] = BroadcastScalarToVector128Int32, + ["BroadcastScalarToVector128.UInt32"] = BroadcastScalarToVector128UInt32, + ["BroadcastScalarToVector128.Int64"] = BroadcastScalarToVector128Int64, + ["BroadcastScalarToVector128.UInt64"] = BroadcastScalarToVector128UInt64, + ["BroadcastScalarToVector128.Single"] = BroadcastScalarToVector128Single, + ["BroadcastScalarToVector128.Double"] = BroadcastScalarToVector128Double, + ["BroadcastScalarToVector256.Byte"] = BroadcastScalarToVector256Byte, + ["BroadcastScalarToVector256.SByte"] = BroadcastScalarToVector256SByte, + ["BroadcastScalarToVector256.Int16"] = BroadcastScalarToVector256Int16, + ["BroadcastScalarToVector256.UInt16"] = BroadcastScalarToVector256UInt16, + ["BroadcastScalarToVector256.Int32"] = BroadcastScalarToVector256Int32, + ["BroadcastScalarToVector256.UInt32"] = BroadcastScalarToVector256UInt32, + ["BroadcastScalarToVector256.Int64"] = BroadcastScalarToVector256Int64, + ["BroadcastScalarToVector256.UInt64"] = BroadcastScalarToVector256UInt64, + ["BroadcastScalarToVector256.Single"] = BroadcastScalarToVector256Single, + ["BroadcastScalarToVector256.Double"] = BroadcastScalarToVector256Double, ["CompareEqual.Byte"] = CompareEqualByte, ["CompareEqual.Int16"] = CompareEqualInt16, ["CompareEqual.Int32"] = CompareEqualInt32, diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index cdd9ba23bd..65ab4e356e 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -13,7 +13,7 @@ using System.IO; // It must be run such from the directory that contains the csx script // // New tests can be generated from the template by adding an entry to the -// appropriate <Isa>Inputs array below. +// appropriate Inputs array below. // // You can support a new Isa by creating a new array and adding a new // "ProcessInputs" call at the bottom of the script. @@ -486,6 +486,31 @@ private static readonly (string templateFileName, string[] templateData)[] Avx2I ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "Average", "Vector256", "UInt16", "Vector256", "UInt16", "Vector256", "UInt16", "32", "(ushort)(random.Next(short.MinValue, short.MaxValue))", "(ushort)(random.Next(short.MinValue, short.MaxValue))", "(ushort)((left[0] + right[0] + 1) >> 1) != result[0]", "(ushort)((left[i] + right[i] + 1) >> 1) != result[i]"}), ("SimpleTernOpTest.template", new string[] { "Avx2", "Avx", "BlendVariable", "Vector256", "Byte", "Vector256", "Byte", "Vector256", "Byte", "Vector256", "Byte", "32", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(((i % 2) == 0) ? 128 : 1)", "((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]", "((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]"}), ("SimpleTernOpTest.template", new string[] { "Avx2", "Avx", "BlendVariable", "Vector256", "SByte", "Vector256", "SByte", "Vector256", "SByte", "Vector256", "SByte", "32", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(((i % 2) == 0) ? -128 : 1)", "((thirdOp[0] >> 7) & 1) == 1 ? secondOp[0] != result[0] : firstOp[0] != result[0]", "((thirdOp[i] >> 7) & 1) == 1 ? secondOp[i] != result[i] : firstOp[i] != result[i]"}), + + + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128", "Vector128","Byte", "Vector128", "Byte", "16", "(byte)(random.Next(0, byte.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128", "Vector128","SByte", "Vector128", "SByte", "16", "(sbyte)(random.Next(0, sbyte.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128", "Vector128","Int16", "Vector128", "Int16", "16", "(short)(random.Next(0, short.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128","Vector128","UInt16","Vector128", "UInt16", "16", "(ushort)(random.Next(0, ushort.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128", "Vector128","Int32", "Vector128", "Int32", "16", "(int)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128","Vector128","UInt32","Vector128", "UInt32", "16", "(uint)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128", "Vector128","Int64", "Vector128", "Int64", "16", "(long)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128","Vector128","UInt64","Vector128", "UInt64", "16", "(ulong)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse", "BroadcastScalarToVector128","Vector128","Single","Vector128", "Single", "16", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[i]))"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector128","Vector128","Double","Vector128", "Double", "16", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])", "(BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[i]))"}), + + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256", "Vector256","Byte", "Vector128", "Byte", "32", "(byte)(random.Next(0, byte.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256", "Vector256","SByte", "Vector128", "SByte", "32", "(sbyte)(random.Next(0, sbyte.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256", "Vector256","Int16", "Vector128", "Int16", "32", "(short)(random.Next(0, short.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256","Vector256","UInt16","Vector128", "UInt16", "32", "(ushort)(random.Next(0, ushort.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256", "Vector256","Int32", "Vector128", "Int32", "32", "(int)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256","Vector256","UInt32","Vector128", "UInt32", "32", "(uint)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256", "Vector256","Int64", "Vector128", "Int64", "32", "(long)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256","Vector256","UInt64","Vector128", "UInt64", "32", "(ulong)(random.Next(0, int.MaxValue))", "firstOp[0] != result[0]", "(firstOp[0] != result[i])"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse", "BroadcastScalarToVector256","Vector256","Single","Vector128", "Single", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[0])", "(BitConverter.SingleToInt32Bits(firstOp[0]) != BitConverter.SingleToInt32Bits(result[i]))"}), + ("GenericUnOpTest.template", new string[] { "Avx2", "Sse2", "BroadcastScalarToVector256","Vector256","Double","Vector128", "Double", "32", "(double)(random.NextDouble())", "BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[0])", "(BitConverter.DoubleToInt64Bits(firstOp[0]) != BitConverter.DoubleToInt64Bits(result[i]))"}), + + ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "CompareEqual", "Vector256", "Byte", "Vector256", "Byte", "Vector256", "Byte", "32", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(random.Next(0, byte.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((byte)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((byte)(-1)) : 0)"}), ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "CompareEqual", "Vector256", "Int16", "Vector256", "Int16", "Vector256", "Int16", "32", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(random.Next(short.MinValue, short.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((short)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((short)(-1)) : 0)"}), ("SimpleBinOpTest.template", new string[] { "Avx2", "Avx", "CompareEqual", "Vector256", "Int32", "Vector256", "Int32", "Vector256", "Int32", "32", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(random.Next(int.MinValue, int.MaxValue))", "result[0] != ((left[0] == right[0]) ? unchecked((int)(-1)) : 0)", "result[i] != ((left[i] == right[i]) ? unchecked((int)(-1)) : 0)"}), diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenericUnOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenericUnOpTest.template new file mode 100644 index 0000000000..a1ec142220 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenericUnOpTest.template @@ -0,0 +1,309 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{{ + public static partial class Program + {{ + private static void {2}{4}() + {{ + var test = new SimpleUnaryOpTest__{2}{4}(); + + if (test.IsSupported) + {{ + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if ({1}.IsSupported) + {{ + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + }} + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if ({1}.IsSupported) + {{ + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + }} + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if ({1}.IsSupported) + {{ + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + }} + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + }} + else + {{ + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + }} + + if (!test.Succeeded) + {{ + throw new Exception("One or more scenarios did not complete as expected."); + }} + }} + }} + + public sealed unsafe class SimpleUnaryOpTest__{2}{4} + {{ + private const int VectorSize = {7}; + + private const int Op1ElementCount = VectorSize / sizeof({6}); + private const int RetElementCount = VectorSize / sizeof({4}); + + private static {6}[] _data = new {6}[Op1ElementCount]; + + private static {5}<{6}> _clsVar; + + private {5}<{6}> _fld; + + private SimpleUnaryOpTest__DataTable<{4}, {6}> _dataTable; + + static SimpleUnaryOpTest__{2}{4}() + {{ + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _clsVar), ref Unsafe.As<{6}, byte>(ref _data[0]), VectorSize); + }} + + public SimpleUnaryOpTest__{2}{4}() + {{ + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{5}<{6}>, byte>(ref _fld), ref Unsafe.As<{6}, byte>(ref _data[0]), VectorSize); + + for (var i = 0; i < Op1ElementCount; i++) {{ _data[i] = {8}; }} + _dataTable = new SimpleUnaryOpTest__DataTable<{4}, {6}>(_data, new {4}[RetElementCount], VectorSize); + }} + + public bool IsSupported => {0}.IsSupported; + + public bool Succeeded {{ get; set; }} + + public void RunBasicScenario_UnsafeRead() + {{ + var result = {0}.{2}<{4}>( + Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunBasicScenario_Load() + {{ + var result = {0}.{2}<{4}>( + {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunBasicScenario_LoadAligned() + {{ + var result = {0}.{2}<{4}>( + {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_UnsafeRead() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2})) + .MakeGenericMethod( new Type[] {{ typeof({6}) }}) + .Invoke(null, new object[] {{ + Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr) + }}); + + Unsafe.Write(_dataTable.outArrayPtr, ({3}<{4}>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_Load() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2})) + .MakeGenericMethod( new Type[] {{ typeof({6}) }}) + .Invoke(null, new object[] {{ + {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)) + }}); + + Unsafe.Write(_dataTable.outArrayPtr, ({3}<{4}>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunReflectionScenario_LoadAligned() + {{ + var result = typeof({0}).GetMethod(nameof({0}.{2})) + .MakeGenericMethod( new Type[] {{ typeof({6}) }}) + .Invoke(null, new object[] {{ + {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)) + }}); + + Unsafe.Write(_dataTable.outArrayPtr, ({3}<{4}>)(result)); + ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr); + }} + + public void RunClsVarScenario() + {{ + var result = {0}.{2}<{4}>( + _clsVar + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar, _dataTable.outArrayPtr); + }} + + public void RunLclVarScenario_UnsafeRead() + {{ + var firstOp = Unsafe.Read<{5}<{6}>>(_dataTable.inArrayPtr); + var result = {0}.{2}<{4}>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + }} + + public void RunLclVarScenario_Load() + {{ + var firstOp = {1}.Load{5}(({6}*)(_dataTable.inArrayPtr)); + var result = {0}.{2}<{4}>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + }} + + public void RunLclVarScenario_LoadAligned() + {{ + var firstOp = {1}.LoadAligned{5}(({6}*)(_dataTable.inArrayPtr)); + var result = {0}.{2}<{4}>(firstOp); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(firstOp, _dataTable.outArrayPtr); + }} + + public void RunLclFldScenario() + {{ + var test = new SimpleUnaryOpTest__{2}{4}(); + var result = {0}.{2}<{4}>(test._fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld, _dataTable.outArrayPtr); + }} + + public void RunFldScenario() + {{ + var result = {0}.{2}<{4}>(_fld); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld, _dataTable.outArrayPtr); + }} + + public void RunUnsupportedScenario() + {{ + Succeeded = false; + + try + {{ + RunBasicScenario_UnsafeRead(); + }} + catch (PlatformNotSupportedException) + {{ + Succeeded = true; + }} + }} + + private void ValidateResult({5}<{6}> firstOp, void* result, [CallerMemberName] string method = "") + {{ + {6}[] inArray = new {6}[Op1ElementCount]; + {4}[] outArray = new {4}[RetElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + }} + + private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "") + {{ + {6}[] inArray = new {6}[Op1ElementCount]; + {4}[] outArray = new {4}[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{6}, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize); + + ValidateResult(inArray, outArray, method); + }} + + private void ValidateResult({6}[] firstOp, {4}[] result, [CallerMemberName] string method = "") + {{ + if ({9}) + {{ + Succeeded = false; + }} + else + {{ + for (var i = 1; i < RetElementCount; i++) + {{ + if ({10}) + {{ + Succeeded = false; + break; + }} + }} + }} + + if (!Succeeded) + {{ + Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{4}>({5}<{6}>): {{method}} failed:"); + Console.WriteLine($" firstOp: ({{string.Join(", ", firstOp)}})"); + Console.WriteLine($" result: ({{string.Join(", ", result)}})"); + Console.WriteLine(); + }} + }} + }} +}} |