Implement AVX SetVector256
authorFei Peng <fei.peng@intel.com>
Mon, 19 Mar 2018 07:17:31 +0000 (00:17 -0700)
committerTanner Gooding <tagoo@outlook.com>
Thu, 22 Mar 2018 16:03:09 +0000 (09:03 -0700)
src/jit/hwintrinsicxarch.cpp
tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_r.csproj [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_ro.csproj [new file with mode: 0644]

index 75eaf1f..f06ca0d 100644 (file)
@@ -1166,6 +1166,55 @@ GenTree* Compiler::impAvxOrAvx2Intrinsic(NamedIntrinsic        intrinsic,
             break;
         }
 
+        case NI_AVX_SetVector256:
+        {
+            // TODO-XARCH: support long/ulong on 32-bit platfroms (remove HW_Flag_SecondArgMaybe64Bit)
+            int numArgs = sig->numArgs;
+            assert(numArgs >= 4);
+            assert(numArgs <= 32);
+            baseType                  = getBaseTypeOfSIMDType(sig->retTypeSigClass);
+            GenTree* higherHalfVector = gtNewSimdHWIntrinsicNode(TYP_SIMD16, NI_SSE_SetZeroVector128, TYP_FLOAT, 16);
+            GenTree* lowerHalfVector  = gtNewSimdHWIntrinsicNode(TYP_SIMD16, NI_SSE_SetZeroVector128, TYP_FLOAT, 16);
+            NamedIntrinsic insertIntrinsic = varTypeIsShort(baseType) ? NI_SSE2_Insert : NI_SSE41_Insert;
+            int            ival            = 0;
+
+            if (baseType != TYP_DOUBLE)
+            {
+                assert(varTypeIsIntegral(baseType) || baseType == TYP_FLOAT);
+
+                for (int i = 0; i < numArgs / 2; i++)
+                {
+                    GenTree* arg = impPopStack().val;
+                    // SSE4.1 insertps has different semantics from integral insert
+                    ival            = baseType == TYP_FLOAT ? i * 16 : i;
+                    lowerHalfVector = gtNewSimdHWIntrinsicNode(TYP_SIMD16, lowerHalfVector, arg, gtNewIconNode(ival),
+                                                               insertIntrinsic, baseType, 16);
+                }
+
+                for (int i = 0; i < numArgs / 2; i++)
+                {
+                    GenTree* arg = impPopStack().val;
+                    // SSE4.1 insertps has different semantics from integral insert
+                    ival             = baseType == TYP_FLOAT ? i * 16 : i;
+                    higherHalfVector = gtNewSimdHWIntrinsicNode(TYP_SIMD16, higherHalfVector, arg, gtNewIconNode(ival),
+                                                                insertIntrinsic, baseType, 16);
+                }
+            }
+            else
+            {
+                GenTree* op4     = impPopStack().val;
+                GenTree* op3     = impPopStack().val;
+                GenTree* op2     = impPopStack().val;
+                GenTree* op1     = impPopStack().val;
+                lowerHalfVector  = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op4, op3, NI_SSE2_UnpackLow, TYP_DOUBLE, 16);
+                higherHalfVector = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, NI_SSE2_UnpackLow, TYP_DOUBLE, 16);
+            }
+
+            retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD32, lowerHalfVector, higherHalfVector, gtNewIconNode(1),
+                                               NI_AVX_InsertVector128, baseType, 32);
+            break;
+        }
+
         case NI_AVX_ExtractVector128:
         case NI_AVX2_ExtractVector128:
         {
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256.cs
new file mode 100644 (file)
index 0000000..73aa3d2
--- /dev/null
@@ -0,0 +1,255 @@
+// 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] { float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN, float.NaN }))
+                {
+                    var vf1 = Avx.SetVector256((float)1, -5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(floatTable.outArrayPtr, vf1);
+
+                    if (!floatTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                       (x[4] == 0) && (x[5] == 100) && (x[6] == -5) && (x[7] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 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] { double.NaN, double.NaN, double.NaN, double.NaN }))
+                {
+                    var vf1 = Avx.SetVector256((double)1, 2, 3, 4);
+                    Unsafe.Write(doubleTable.outArrayPtr, vf1);
+
+                    if (!doubleTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on double:");
+                        foreach (var item in doubleTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<sbyte> sbyteTable = new TestTable<sbyte>(new sbyte[32] { sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue,
+                                                                                          sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue,
+                                                                                          sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue,
+                                                                                          sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue, sbyte.MaxValue }))
+                {
+                    var vf1 = Avx.SetVector256(1, -5, 100, 0, 1, 2, 3, 4, 1, -5, 100, 0, 1, 2, 3, 4, 1, -5, 100, 0, 1, 2, 3, 4, 1, -5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(sbyteTable.outArrayPtr, vf1);
+
+                    if (!sbyteTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                       (x[4] == 0) && (x[5] == 100) && (x[6] == -5) && (x[7] == 1) &&
+                                                       (x[8] == 4) && (x[9] == 3) && (x[10] == 2) && (x[11] == 1) &&
+                                                       (x[12] == 0) && (x[13] == 100) && (x[14] == -5) && (x[15] == 1) &&
+                                                       (x[16] == 4) && (x[17] == 3) && (x[18] == 2) && (x[19] == 1) &&
+                                                       (x[20] == 0) && (x[21] == 100) && (x[22] == -5) && (x[23] == 1) &&
+                                                       (x[24] == 4) && (x[25] == 3) && (x[26] == 2) && (x[27] == 1) &&
+                                                       (x[28] == 0) && (x[29] == 100) && (x[30] == -5) && (x[31] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on sbyte:");
+                        foreach (var item in sbyteTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<byte> byteTable = new TestTable<byte>(new byte[32] { byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue,
+                                                                                      byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue,
+                                                                                      byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue,
+                                                                                      byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue }))
+                {
+                    Vector256<byte> vf1 = Avx.SetVector256((byte)1, 5, 100, 0, 1, 2, 3, 4, 1, 5, 100, 0, 1, 2, 3, 4, 1, 5, 100, 0, 1, 2, 3, 4, 1, 5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(byteTable.outArrayPtr, vf1);
+
+                    if (!byteTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                       (x[4] == 0) && (x[5] == 100) && (x[6] == 5) && (x[7] == 1) &&
+                                                       (x[8] == 4) && (x[9] == 3) && (x[10] == 2) && (x[11] == 1) &&
+                                                       (x[12] == 0) && (x[13] == 100) && (x[14] == 5) && (x[15] == 1) &&
+                                                       (x[16] == 4) && (x[17] == 3) && (x[18] == 2) && (x[19] == 1) &&
+                                                       (x[20] == 0) && (x[21] == 100) && (x[22] == 5) && (x[23] == 1) &&
+                                                       (x[24] == 4) && (x[25] == 3) && (x[26] == 2) && (x[27] == 1) &&
+                                                       (x[28] == 0) && (x[29] == 100) && (x[30] == 5) && (x[31] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on byte:");
+                        foreach (var item in byteTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<short> shortTable = new TestTable<short>(new short[16] { short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue,
+                                                                                          short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue, short.MaxValue }))
+                {
+                    var vf1 = Avx.SetVector256(1, -5, 100, 0, 1, 2, 3, 4, 1, -5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(shortTable.outArrayPtr, vf1);
+
+                    if (!shortTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                       (x[4] == 0) && (x[5] == 100) && (x[6] == -5) && (x[7] == 1) &&
+                                                       (x[8] == 4) && (x[9] == 3) && (x[10] == 2) && (x[11] == 1) &&
+                                                       (x[12] == 0) && (x[13] == 100) && (x[14] == -5) && (x[15] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on short:");
+                        foreach (var item in shortTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<ushort> ushortTable = new TestTable<ushort>(new ushort[16] { ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue,
+                                                                                              ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue }))
+                {
+                    Vector256<ushort> vf1 = Avx.SetVector256((ushort)1, 5, 100, 0, 1, 2, 3, 4, 1, 5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(ushortTable.outArrayPtr, vf1);
+
+                    if (!ushortTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                       (x[4] == 0) && (x[5] == 100) && (x[6] == 5) && (x[7] == 1) &&
+                                                       (x[8] == 4) && (x[9] == 3) && (x[10] == 2) && (x[11] == 1) &&
+                                                       (x[12] == 0) && (x[13] == 100) && (x[14] == 5) && (x[15] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on ushort:");
+                        foreach (var item in ushortTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<int> intTable = new TestTable<int>(new int[8] { int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue }))
+                {
+                    var vf1 = Avx.SetVector256(1, -5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(intTable.outArrayPtr, vf1);
+
+                    if (!intTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                     (x[4] == 0) && (x[5] == 100) && (x[6] == -5) && (x[7] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on int:");
+                        foreach (var item in intTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<uint> uintTable = new TestTable<uint>(new uint[8] { uint.MaxValue, uint.MaxValue, uint.MaxValue, uint.MaxValue, uint.MaxValue, uint.MaxValue, uint.MaxValue, uint.MaxValue }))
+                {
+                    Vector256<uint> vf1 = Avx.SetVector256((uint)1, 5, 100, 0, 1, 2, 3, 4);
+                    Unsafe.Write(uintTable.outArrayPtr, vf1);
+
+                    if (!uintTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1) &&
+                                                     (x[4] == 0) && (x[5] == 100) && (x[6] == 5) && (x[7] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on uint:");
+                        foreach (var item in uintTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<long> longTable = new TestTable<long>(new long[4] { long.MaxValue, long.MaxValue, long.MaxValue, long.MaxValue }))
+                {
+                    var vf1 = Avx.SetVector256(1, 2, 3, 4);
+                    Unsafe.Write(longTable.outArrayPtr, vf1);
+
+                    if (!longTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on long:");
+                        foreach (var item in longTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+
+                using (TestTable<ulong> ulongTable = new TestTable<ulong>(new ulong[4] { ulong.MaxValue, ulong.MaxValue, ulong.MaxValue, ulong.MaxValue }))
+                {
+                    Vector256<ulong> vf1 = Avx.SetVector256((ulong)1, 2, 3, 4);
+                    Unsafe.Write(ulongTable.outArrayPtr, vf1);
+
+                    if (!ulongTable.CheckResult((x) => (x[0] == 4) && (x[1] == 3) && (x[2] == 2) && (x[3] == 1)))
+                    {
+                        Console.WriteLine("AVX SetVector256 failed on ulong:");
+                        foreach (var item in ulongTable.outArray)
+                        {
+                            Console.Write(item + ", ");
+                        }
+                        Console.WriteLine();
+                        testResult = Fail;
+                    }
+                }
+            }
+
+            return testResult;
+        }
+
+        public unsafe struct TestTable<T> : IDisposable where T : struct
+        {
+            public T[] outArray;
+
+            public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer();
+
+            GCHandle outHandle;
+            public TestTable(T[] a)
+            {
+                this.outArray = a;
+
+                outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned);
+            }
+            public bool CheckResult(Func<T[], bool> check)
+            {
+                return check(outArray);
+            }
+
+            public void Dispose()
+            {
+                outHandle.Free();
+            }
+        }
+
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_r.csproj
new file mode 100644 (file)
index 0000000..5bcc47e
--- /dev/null
@@ -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="SetVector256.cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx/SetVector256_ro.csproj
new file mode 100644 (file)
index 0000000..be90a48
--- /dev/null
@@ -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="SetVector256.cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>