Re-enable hardware intrinsic tests
authorFei Peng <fei.peng@intel.com>
Thu, 27 Sep 2018 23:54:10 +0000 (16:54 -0700)
committerFei Peng <fei.peng@intel.com>
Fri, 28 Sep 2018 00:00:47 +0000 (17:00 -0700)
tests/arm/Tests.lst
tests/arm64/Tests.lst
tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx
tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj
tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs [new file with mode: 0644]

index ee226c9..a5c162e 100644 (file)
@@ -91100,6 +91100,14 @@ MaxAllowedDurationSeconds=600
 Categories=EXPECTED_PASS;NEW;EXCLUDED
 HostStyle=0
 
+[Popcnt_r.cmd_11492]
+RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_r\Popcnt_r.cmd
+WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_r
+Expected=0
+MaxAllowedDurationSeconds=600
+Categories=EXPECTED_PASS;NEW;EXCLUDED
+HostStyle=0
+
 [StoreLow_r.cmd_11493]
 RelativePath=JIT\HardwareIntrinsics\X86\Sse2\StoreLow_r\StoreLow_r.cmd
 WorkingDir=JIT\HardwareIntrinsics\X86\Sse2\StoreLow_r
@@ -93340,6 +93348,14 @@ MaxAllowedDurationSeconds=600
 Categories=EXPECTED_PASS;NEW;EXCLUDED
 HostStyle=0
 
+[Popcnt_ro.cmd_11829]
+RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro\Popcnt_ro.cmd
+WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro
+Expected=0
+MaxAllowedDurationSeconds=600
+Categories=EXPECTED_PASS;NEW;EXCLUDED
+HostStyle=0
+
 [MoveHighAndDuplicate_ro.cmd_11830]
 RelativePath=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro\MoveHighAndDuplicate_ro.cmd
 WorkingDir=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro
index 9f12dfd..f30f524 100644 (file)
@@ -93308,6 +93308,14 @@ MaxAllowedDurationSeconds=600
 Categories=EXPECTED_PASS;NEW;EXCLUDED
 HostStyle=0
 
+[MultiplyHorizontalAdd_ro.cmd_12141]
+RelativePath=JIT\HardwareIntrinsics\X86\Sse2\MultiplyHorizontalAdd_ro\MultiplyHorizontalAdd_ro.cmd
+WorkingDir=JIT\HardwareIntrinsics\X86\Sse2\MultiplyHorizontalAdd_ro
+Expected=0
+MaxAllowedDurationSeconds=600
+Categories=EXPECTED_PASS;NEW;EXCLUDED
+HostStyle=0
+
 [MoveHighToLow_r.cmd_12142]
 RelativePath=JIT\HardwareIntrinsics\X86\Sse\MoveHighToLow_r\MoveHighToLow_r.cmd
 WorkingDir=JIT\HardwareIntrinsics\X86\Sse\MoveHighToLow_r
@@ -93332,6 +93340,14 @@ MaxAllowedDurationSeconds=600
 Categories=EXPECTED_PASS;NEW;EXCLUDED
 HostStyle=0
 
+[Popcnt_ro.cmd_12145]
+RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro\Popcnt_ro.cmd
+WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro
+Expected=0
+MaxAllowedDurationSeconds=600
+Categories=EXPECTED_PASS;NEW;EXCLUDED
+HostStyle=0
+
 [MoveHighAndDuplicate_ro.cmd_12146]
 RelativePath=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro\MoveHighAndDuplicate_ro.cmd
 WorkingDir=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs
new file mode 100644 (file)
index 0000000..e30a8ed
--- /dev/null
@@ -0,0 +1,131 @@
+// 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.Reflection;
+using System.Runtime.Intrinsics.X86;
+
+namespace IntelHardwareIntrinsicTest
+{
+    class Program
+    {
+        const int Pass = 100;
+        const int Fail = 0;
+
+        static int Main(string[] args)
+        {
+            ulong sl = 0;
+            ulong resl;
+            int testResult = Pass;
+
+            if (!Popcnt.IsSupported || !Environment.Is64BitProcess)
+            {
+                try
+                {
+                    resl = Popcnt.PopCount(sl);
+                    Console.WriteLine("Intrinsic Popcnt.PopCount is called on non-supported hardware");
+                    Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported);
+                    Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess);
+                    testResult = Fail;
+                }
+                catch (PlatformNotSupportedException)
+                {
+                }
+
+                try
+                {
+                    resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl }));
+                    Console.WriteLine("Intrinsic Popcnt.PopCount is called via reflection on non-supported hardware");
+                    Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported);
+                    Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess);
+                    testResult = Fail;
+                }
+                catch (TargetInvocationException e) when (e.InnerException is PlatformNotSupportedException)
+                {
+                }
+            }
+
+
+            if (Popcnt.IsSupported)
+            {
+                if (Environment.Is64BitProcess)
+                {
+                    for (int i = 0; i < longPopcntTable.Length; i++)
+                    {
+                        sl = longPopcntTable[i].s;
+
+                        resl = Popcnt.PopCount(sl);
+                        if (resl != longPopcntTable[i].res)
+                        {
+                            Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}",
+                                i, sl, longPopcntTable[i].res, resl);
+                            testResult = Fail;
+                        }
+
+                        resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl }));
+                        if (resl != longPopcntTable[i].res)
+                        {
+                            Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection",
+                                i, sl, longPopcntTable[i].res, resl);
+                            testResult = Fail;
+                        }
+                    }
+                }
+
+                uint si;
+                uint resi;
+                for (int i = 0; i < intPopcntTable.Length; i++)
+                {
+                    si = intPopcntTable[i].s;
+
+                    resi = Popcnt.PopCount(si);
+                    if (resi != intPopcntTable[i].res)
+                    {
+                        Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}",
+                            i, si, intPopcntTable[i].res, resi);
+                        testResult = Fail;
+                    }
+
+                    resi = Convert.ToUInt32(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { si.GetType() }).Invoke(null, new object[] { si }));
+                    if (resi != intPopcntTable[i].res)
+                    {
+                        Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection",
+                            i, si, intPopcntTable[i].res, resi);
+                        testResult = Fail;
+                    }
+                }
+            }
+
+            return testResult;
+        }
+
+        public struct POPCNT<T, U> where T : struct where U : struct
+        {
+            public T s;
+            public U res;
+            public POPCNT(T a, U r)
+            {
+                this.s = a;
+                this.res = r;
+            }
+        }
+
+        public static POPCNT<ulong,ulong>[] longPopcntTable = {
+            new POPCNT<ulong,ulong>(0x0000000000000000UL, 0UL),
+            new POPCNT<ulong,ulong>(0x0000000000000001UL, 1UL),
+            new POPCNT<ulong,ulong>(0xffffffffffffffffUL, 64UL),
+            new POPCNT<ulong,ulong>(0x8000000000000000UL, 1UL),
+            new POPCNT<ulong,ulong>(0x00050000000f423fUL, 14UL)
+        };
+
+        public static POPCNT<uint,uint>[] intPopcntTable = {
+            new POPCNT<uint,uint>(0x00000000U, 0U),
+            new POPCNT<uint,uint>(0x00000001U, 1U),
+            new POPCNT<uint,uint>(0xffffffffU, 32U),
+            new POPCNT<uint,uint>(0x80000000U, 1U),
+            new POPCNT<uint,uint>(0x0005423fU, 10U)
+        };
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj
new file mode 100644 (file)
index 0000000..e32ab7a
--- /dev/null
@@ -0,0 +1,33 @@
+<?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>
+  </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>Embedded</DebugType>
+    <Optimize></Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Popcnt.cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj
new file mode 100644 (file)
index 0000000..a53bf1b
--- /dev/null
@@ -0,0 +1,33 @@
+<?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>
+  </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>Embedded</DebugType>
+    <Optimize>True</Optimize>
+  </PropertyGroup>
+  <ItemGroup>
+    <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+  </ItemGroup>
+  <ItemGroup>
+    <Compile Include="Popcnt.cs" />
+  </ItemGroup>
+  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+  <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
index 469dddb..d99bd66 100644 (file)
@@ -194,6 +194,7 @@ private static readonly (string templateFileName, Dictionary<string, string> tem
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MinScalar",                                ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Math.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])",                           ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Multiply",                                 ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])",                                    ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyScalar",                           ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])",                                    ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
+    ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyAddAdjacent",                      ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32",  ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16",  ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16",                                           ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()",  ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()",  ["ValidateFirstResult"] = "result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue)",                                 ["ValidateRemainingResults"] = "result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue)"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or",                                       ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "(BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])",  ["ValidateRemainingResults"] = "(BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or",                                       ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte",   ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte",   ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte",                                            ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()",   ["NextValueOp2"] = "TestLibrary.Generator.GetByte()",   ["ValidateFirstResult"] = "(byte)(left[0] | right[0]) != result[0]",                                                                                            ["ValidateRemainingResults"] = "(byte)(left[i] | right[i]) != result[i]"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or",                                       ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16",  ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16",  ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16",                                           ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()",  ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()",  ["ValidateFirstResult"] = "(short)(left[0] | right[0]) != result[0]",                                                                                           ["ValidateRemainingResults"] = "(short)(left[i] | right[i]) != result[i]"}),
@@ -273,6 +274,7 @@ private static readonly (string templateFileName, Dictionary<string, string> tem
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate",                         ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16",  ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16",  ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16",                                           ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()",  ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()",  ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])",                                                                          ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate",                         ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])",                                                                          ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractScalar",                           ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])",                                    ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
+    ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SumAbsoluteDifferences",                   ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte",   ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte",                                            ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()",  ["NextValueOp2"] = "TestLibrary.Generator.GetByte()",    ["ValidateFirstResult"] = "result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7])",    ["ValidateRemainingResults"] = "result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15]))"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh",                               ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(left[1])",                                               ["ValidateRemainingResults"] = "(i % 2 == 0) ? BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i/2+1]) : BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(right[(i - 1)/2 + 1])"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh",                               ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64",  ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64",  ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64",                                           ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()",  ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()",  ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]",                                                                                      ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}),
     ("SimpleBinOpTest.template",        new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh",                               ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64",                                          ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]",                                                                                      ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}),
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs
new file mode 100644 (file)
index 0000000..49dd651
--- /dev/null
@@ -0,0 +1,403 @@
+// 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 MultiplyAddAdjacentInt32()
+        {
+            var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32();
+
+            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 class works
+                test.RunClassLclFldScenario();
+
+                // Validates passing an instance member of a class works
+                test.RunClassFldScenario();
+
+                // Validates passing the field of a local struct works
+                test.RunStructLclFldScenario();
+
+                // Validates passing an instance member of a struct works
+                test.RunStructFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__MultiplyAddAdjacentInt32
+    {
+        private struct TestStruct
+        {
+            public Vector128<Int16> _fld1;
+            public Vector128<Int16> _fld2;
+
+            public static TestStruct Create()
+            {
+                var testStruct = new TestStruct();
+
+                for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+                Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref testStruct._fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+                for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+                Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref testStruct._fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+                return testStruct;
+            }
+
+            public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyAddAdjacentInt32 testClass)
+            {
+                var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2);
+
+                Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+                testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+            }
+        }
+
+        private static readonly int LargestVectorSize = 16;
+
+        private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+        private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+        private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+
+        private static Int16[] _data1 = new Int16[Op1ElementCount];
+        private static Int16[] _data2 = new Int16[Op2ElementCount];
+
+        private static Vector128<Int16> _clsVar1;
+        private static Vector128<Int16> _clsVar2;
+
+        private Vector128<Int16> _fld1;
+        private Vector128<Int16> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Int32, Int16, Int16> _dataTable;
+
+        static SimpleBinaryOpTest__MultiplyAddAdjacentInt32()
+        {
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+        }
+
+        public SimpleBinaryOpTest__MultiplyAddAdjacentInt32()
+        {
+            Succeeded = true;
+
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int16, Int16>(_data1, _data2, new Int32[RetElementCount], LargestVectorSize);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+            var result = Sse2.MultiplyAddAdjacent(
+                Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunBasicScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+            var result = Sse2.MultiplyAddAdjacent(
+                Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+                Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr))
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunBasicScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+            var result = Sse2.MultiplyAddAdjacent(
+                Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+                Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr))
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+                                     .Invoke(null, new object[] {
+                                        Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+                                        Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr))
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+                                     .Invoke(null, new object[] {
+                                        Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+                                        Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr))
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunClsVarScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+            var result = Sse2.MultiplyAddAdjacent(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+            var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr);
+            var result = Sse2.MultiplyAddAdjacent(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+            var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr));
+            var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr));
+            var result = Sse2.MultiplyAddAdjacent(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+            var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr));
+            var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr));
+            var result = Sse2.MultiplyAddAdjacent(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunClassLclFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+            var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32();
+            var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunClassFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+            var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunStructLclFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+            var test = TestStruct.Create();
+            var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunStructFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+            var test = TestStruct.Create();
+            test.RunStructFldScenario(this);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario_UnsafeRead();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "")
+        {
+            Int16[] inArray1 = new Int16[Op1ElementCount];
+            Int16[] inArray2 = new Int16[Op2ElementCount];
+            Int32[] outArray = new Int32[RetElementCount];
+
+            Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), left);
+            Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), right);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+            ValidateResult(inArray1, inArray2, outArray, method);
+        }
+
+        private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+        {
+            Int16[] inArray1 = new Int16[Op1ElementCount];
+            Int16[] inArray2 = new Int16[Op2ElementCount];
+            Int32[] outArray = new Int32[RetElementCount];
+
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+            ValidateResult(inArray1, inArray2, outArray, method);
+        }
+
+        private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "")
+        {
+            if (result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue))
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < RetElementCount; i++)
+                {
+                    if (result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue))
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.MultiplyAddAdjacent)}<Int32>(Vector128<Int16>, Vector128<Int16>): {method} failed:");
+                TestLibrary.TestFramework.LogInformation($"    left: ({string.Join(", ", left)})");
+                TestLibrary.TestFramework.LogInformation($"   right: ({string.Join(", ", right)})");
+                TestLibrary.TestFramework.LogInformation($"  result: ({string.Join(", ", result)})");
+                TestLibrary.TestFramework.LogInformation(string.Empty);
+            }
+        }
+    }
+}
index aacdaa3..8822656 100644 (file)
@@ -129,6 +129,7 @@ namespace JIT.HardwareIntrinsics.X86
                 ["MinScalar.Double"] = MinScalarDouble,
                 ["Multiply.Double"] = MultiplyDouble,
                 ["MultiplyScalar.Double"] = MultiplyScalarDouble,
+                ["MultiplyAddAdjacent.Int32"] = MultiplyAddAdjacentInt32,
                 ["Or.Double"] = OrDouble,
                 ["Or.Byte"] = OrByte,
                 ["Or.Int16"] = OrInt16,
@@ -208,6 +209,7 @@ namespace JIT.HardwareIntrinsics.X86
                 ["SubtractSaturate.Int16"] = SubtractSaturateInt16,
                 ["SubtractSaturate.UInt16"] = SubtractSaturateUInt16,
                 ["SubtractScalar.Double"] = SubtractScalarDouble,
+                ["SumAbsoluteDifferences.UInt16"] = SumAbsoluteDifferencesUInt16,
                 ["UnpackHigh.Double"] = UnpackHighDouble,
                 ["UnpackHigh.Int64"] = UnpackHighInt64,
                 ["UnpackHigh.UInt64"] = UnpackHighUInt64,
index b9101fc..a864813 100644 (file)
     <Compile Include="MinScalar.Double.cs" />
     <Compile Include="Multiply.Double.cs" />
     <Compile Include="MultiplyScalar.Double.cs" />
+    <Compile Include="MultiplyAddAdjacent.Int32.cs" />
     <Compile Include="Or.Double.cs" />
     <Compile Include="Or.Byte.cs" />
     <Compile Include="Or.Int16.cs" />
     <Compile Include="SubtractSaturate.Int16.cs"/>
     <Compile Include="SubtractSaturate.UInt16.cs"/>
     <Compile Include="SubtractScalar.Double.cs" />
+    <Compile Include="SumAbsoluteDifferences.UInt16.cs" />
     <Compile Include="UnpackHigh.Double.cs" />
     <Compile Include="UnpackHigh.Int64.cs" />
     <Compile Include="UnpackHigh.UInt64.cs" />
index 563bc43..7b894da 100644 (file)
     <Compile Include="MinScalar.Double.cs" />
     <Compile Include="Multiply.Double.cs" />
     <Compile Include="MultiplyScalar.Double.cs" />
+    <Compile Include="MultiplyAddAdjacent.Int32.cs" />
     <Compile Include="Or.Byte.cs" />
     <Compile Include="Or.Double.cs" />
     <Compile Include="Or.Int16.cs" />
     <Compile Include="SubtractSaturate.SByte.cs"/>
     <Compile Include="SubtractSaturate.UInt16.cs"/>
     <Compile Include="SubtractScalar.Double.cs" />
+    <Compile Include="SumAbsoluteDifferences.UInt16.cs" />
     <Compile Include="UnpackHigh.Double.cs" />
     <Compile Include="UnpackHigh.Int64.cs" />
     <Compile Include="UnpackHigh.UInt64.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs
new file mode 100644 (file)
index 0000000..be18337
--- /dev/null
@@ -0,0 +1,403 @@
+// 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 SumAbsoluteDifferencesUInt16()
+        {
+            var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16();
+
+            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 class works
+                test.RunClassLclFldScenario();
+
+                // Validates passing an instance member of a class works
+                test.RunClassFldScenario();
+
+                // Validates passing the field of a local struct works
+                test.RunStructLclFldScenario();
+
+                // Validates passing an instance member of a struct works
+                test.RunStructFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16
+    {
+        private struct TestStruct
+        {
+            public Vector128<Byte> _fld1;
+            public Vector128<Byte> _fld2;
+
+            public static TestStruct Create()
+            {
+                var testStruct = new TestStruct();
+
+                for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+                Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref testStruct._fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+                for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+                Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref testStruct._fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+
+                return testStruct;
+            }
+
+            public void RunStructFldScenario(SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16 testClass)
+            {
+                var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2);
+
+                Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+                testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+            }
+        }
+
+        private static readonly int LargestVectorSize = 16;
+
+        private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Byte>>() / sizeof(Byte);
+        private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Byte>>() / sizeof(Byte);
+        private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+
+        private static Byte[] _data1 = new Byte[Op1ElementCount];
+        private static Byte[] _data2 = new Byte[Op2ElementCount];
+
+        private static Vector128<Byte> _clsVar1;
+        private static Vector128<Byte> _clsVar2;
+
+        private Vector128<Byte> _fld1;
+        private Vector128<Byte> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<UInt16, Byte, Byte> _dataTable;
+
+        static SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16()
+        {
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+        }
+
+        public SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16()
+        {
+            Succeeded = true;
+
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+
+            for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+            for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<UInt16, Byte, Byte>(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+            var result = Sse2.SumAbsoluteDifferences(
+                Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunBasicScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+            var result = Sse2.SumAbsoluteDifferences(
+                Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)),
+                Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr))
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunBasicScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+            var result = Sse2.SumAbsoluteDifferences(
+                Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)),
+                Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr))
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+                                     .Invoke(null, new object[] {
+                                        Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)),
+                                        Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr))
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunReflectionScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+                                     .Invoke(null, new object[] {
+                                        Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)),
+                                        Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr))
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+            ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+        }
+
+        public void RunClsVarScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+            var result = Sse2.SumAbsoluteDifferences(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_UnsafeRead()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+            var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr);
+            var result = Sse2.SumAbsoluteDifferences(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_Load()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+            var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr));
+            var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr));
+            var result = Sse2.SumAbsoluteDifferences(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunLclVarScenario_LoadAligned()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+            var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr));
+            var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr));
+            var result = Sse2.SumAbsoluteDifferences(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArrayPtr);
+        }
+
+        public void RunClassLclFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+            var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16();
+            var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunClassFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+            var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunStructLclFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+            var test = TestStruct.Create();
+            var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+        }
+
+        public void RunStructFldScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+            var test = TestStruct.Create();
+            test.RunStructFldScenario(this);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario_UnsafeRead();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "")
+        {
+            Byte[] inArray1 = new Byte[Op1ElementCount];
+            Byte[] inArray2 = new Byte[Op2ElementCount];
+            UInt16[] outArray = new UInt16[RetElementCount];
+
+            Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), left);
+            Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), right);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+            ValidateResult(inArray1, inArray2, outArray, method);
+        }
+
+        private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+        {
+            Byte[] inArray1 = new Byte[Op1ElementCount];
+            Byte[] inArray2 = new Byte[Op2ElementCount];
+            UInt16[] outArray = new UInt16[RetElementCount];
+
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+            ValidateResult(inArray1, inArray2, outArray, method);
+        }
+
+        private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "")
+        {
+            if (result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7]))
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < RetElementCount; i++)
+                {
+                    if (result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15])))
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.SumAbsoluteDifferences)}<UInt16>(Vector128<Byte>, Vector128<Byte>): {method} failed:");
+                TestLibrary.TestFramework.LogInformation($"    left: ({string.Join(", ", left)})");
+                TestLibrary.TestFramework.LogInformation($"   right: ({string.Join(", ", right)})");
+                TestLibrary.TestFramework.LogInformation($"  result: ({string.Join(", ", result)})");
+                TestLibrary.TestFramework.LogInformation(string.Empty);
+            }
+        }
+    }
+}