Updating the Sse2 HardwareIntrinsic tests to be generated from a template.
authorTanner Gooding <tagoo@outlook.com>
Sat, 27 Jan 2018 19:23:35 +0000 (11:23 -0800)
committerTanner Gooding <tagoo@outlook.com>
Sun, 28 Jan 2018 01:56:37 +0000 (17:56 -0800)
17 files changed:
tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Shared/Program.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.cs [deleted file]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs [new file with mode: 0644]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj [moved from tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add_r.csproj with 77% similarity]
tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj [moved from tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add_ro.csproj with 77% similarity]

diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx
new file mode 100644 (file)
index 0000000..ea4545a
--- /dev/null
@@ -0,0 +1,76 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.IO;
+
+// NOTE: This file isn't very robust and makes several assumptions.
+//       It must be run such that its own directory is the working directory.
+
+private static readonly (string templateFileName, string[] templateData)[] Sse2Inputs = new []
+{
+    // TemplateName                             Isa,    Method, BaseType, VectorType,  VectorSize, NextValue,                                              ValidateFirstResult,                                                                               ValidateRemainingResults
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "Double", "Vector128", "16",       "(double)(random.NextDouble())",                        "BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0])", "BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "Byte",   "Vector128", "16",       "(byte)(random.Next(0, byte.MaxValue))",                "(byte)(left[0] + right[0]) != result[0]",                                                         "(byte)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "Int16",  "Vector128", "16",       "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]",                                                        "(short)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "Int32",  "Vector128", "16",       "(int)(random.Next(int.MinValue, int.MaxValue))",       "(int)(left[0] + right[0]) != result[0]",                                                          "(int)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "Int64",  "Vector128", "16",       "(long)(random.Next(int.MinValue, int.MaxValue))",      "(long)(left[0] + right[0]) != result[0]",                                                         "(long)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "SByte",  "Vector128", "16",       "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]",                                                        "(sbyte)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "UInt16", "Vector128", "16",       "(ushort)(random.Next(0, ushort.MaxValue))",            "(ushort)(left[0] + right[0]) != result[0]",                                                       "(ushort)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "UInt32", "Vector128", "16",       "(uint)(random.Next(0, int.MaxValue))",                 "(uint)(left[0] + right[0]) != result[0]",                                                         "(uint)(left[i] + right[i]) != result[i]"}),
+    ("SimpleBinOpTest.template", new string[] { "Sse2", "Add",  "UInt64", "Vector128", "16",       "(ulong)(random.Next(0, int.MaxValue))",                "(ulong)(left[0] + right[0]) != result[0]",                                                        "(ulong)(left[i] + right[i]) != result[i]"}),
+};
+
+private static void ProcessInputs(string isa, (string templateFileName, string[] templateData)[] inputs)
+{
+    var testListFileName = Path.Combine("..", isa, $"Program.{isa}.cs");
+
+    using (var testListFile = new StreamWriter(testListFileName, append: false))
+    {
+        testListFile.WriteLine(@"// 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.Collections.Generic;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        static Program()
+        {
+            TestList = new Dictionary<string, Action>() {");
+
+        foreach (var input in inputs)
+        {
+            ProcessInput(testListFile, input);
+        }
+
+        testListFile.WriteLine(@"            };
+        }
+    }
+}");
+    }
+}
+
+private static void ProcessInput(StreamWriter testListFile, (string templateFileName, string[] templateData) input)
+{
+    var testName = $"{input.templateData[1]}.{input.templateData[2]}";
+
+    // Ex: ["Add.Single"] = AddSingle
+    testListFile.WriteLine($@"                [""{testName}""] = {input.templateData[1]}{input.templateData[2]},");
+
+    var testFileName = Path.Combine("..", input.templateData[0], $"{testName}.cs");
+    var template = File.ReadAllText(input.templateFileName);
+
+    if (input.templateData.Length != 0)
+    {
+        template = string.Format(template, input.templateData);
+    }
+
+    File.WriteAllText(testFileName, template);
+}
+
+ProcessInputs("Sse2", Sse2Inputs);
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/Program.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/Program.cs
new file mode 100644 (file)
index 0000000..abc8e31
--- /dev/null
@@ -0,0 +1,81 @@
+// 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.Collections.Generic;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private const int PASS = 100;
+        private const int FAIL = 0;
+
+        private static readonly IDictionary<string, Action> TestList;
+
+        public static int Main(string[] args)
+        {
+            var isPassing = true;
+
+            foreach (string testToRun in GetTestsToRun(args))
+            {
+                Console.WriteLine($"Running {testToRun} test...");
+
+                try
+                {
+                    TestList[testToRun].Invoke();
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine($"Error: {e.Message}");
+                    isPassing = false;
+                }
+            }
+
+            return isPassing ? PASS : FAIL;
+        }
+
+        private static ICollection<string> GetTestsToRun(string[] args)
+        {
+            var testsToRun = new HashSet<string>();
+
+            for (var i = 0; i < args.Length; i++)
+            {
+                var testName = args[i].ToLowerInvariant();
+
+                if (testName == "all")
+                {
+                    break;
+                }
+
+                if (!TestList.ContainsKey(testName))
+                {
+                    PrintUsage();
+                }
+
+                testsToRun.Add(testName);
+            }
+
+            return (testsToRun.Count == 0) ? TestList.Keys : testsToRun;
+        }
+
+        private static void PrintUsage()
+        {
+            Console.WriteLine($@"Usage:
+{Environment.GetCommandLineArgs()[0]} [testName]
+
+  [testName]: The name of the function to test.
+              Defaults to 'all'.
+              Multiple can be specified.
+
+  Available Test Names:");
+            foreach (string testName in TestList.Keys)
+            {
+                Console.WriteLine($"    {testName}");
+            }
+
+            Environment.Exit(FAIL);
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest.template
new file mode 100644 (file)
index 0000000..b906a5c
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{{
+    public static partial class Program
+    {{
+        private static void {1}{2}()
+        {{
+            var test = new SimpleBinaryOpTest__{1}{2}();
+
+            if (test.IsSupported)
+            {{
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }}
+            else
+            {{
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }}
+
+            if (!test.Succeeded)
+            {{
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }}
+        }}
+    }}
+
+    public sealed unsafe class SimpleBinaryOpTest__{1}{2}
+    {{
+        private const int VectorSize = {4};
+        private const int ElementCount = VectorSize / sizeof({2});
+
+        private static {2}[] _data1 = new {2}[ElementCount];
+        private static {2}[] _data2 = new {2}[ElementCount];
+
+        private static {3}<{2}> _clsVar1;
+        private static {3}<{2}> _clsVar2;
+
+        private {3}<{2}> _fld1;
+        private {3}<{2}> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<{2}> _dataTable;
+
+        static SimpleBinaryOpTest__{1}{2}()
+        {{
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }}
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar1), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _clsVar2), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize);
+        }}
+
+        public SimpleBinaryOpTest__{1}{2}()
+        {{
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }}
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld1), ref Unsafe.As<{2}, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}<{2}>, byte>(ref _fld2), ref Unsafe.As<{2}, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {5}; _data2[i] = {5}; }}
+            _dataTable = new SimpleBinaryOpTest__DataTable<{2}>(_data1, _data2, new {2}[ElementCount]);
+        }}
+
+        public bool IsSupported => {0}.IsSupported;
+
+        public bool Succeeded {{ get; set; }}
+
+        public void RunBasicScenario()
+        {{
+            var result = {0}.{1}(
+                Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }}
+
+        public void RunReflectionScenario()
+        {{
+            var result = typeof({0}).GetMethod(nameof({0}.{1}), new Type[] {{ typeof({3}<{2}>), typeof({3}<{2}>) }})
+                                     .Invoke(null, new object[] {{
+                                        Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr)
+                                     }});
+
+            Unsafe.Write(_dataTable.outArrayPtr, ({3}<{2}>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }}
+
+        public void RunClsVarScenario()
+        {{
+            var result = {0}.{1}(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }}
+
+        public void RunLclVarScenario()
+        {{
+            var left = Unsafe.Read<{3}<{2}>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<{3}<{2}>>(_dataTable.inArray2Ptr);
+            var result = {0}.{1}(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }}
+
+        public void RunLclFldScenario()
+        {{
+            var test = new SimpleBinaryOpTest__{1}{2}();
+            var result = {0}.{1}(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }}
+
+        public void RunFldScenario()
+        {{
+            var result = {0}.{1}(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }}
+
+        public void RunUnsupportedScenario()
+        {{
+            Succeeded = false;
+
+            try
+            {{
+                RunBasicScenario();
+            }}
+            catch (PlatformNotSupportedException)
+            {{
+                Succeeded = true;
+            }}
+        }}
+
+        private void ValidateResult({3}<{2}> left, {3}<{2}> right, {2}[] result, [CallerMemberName] string method = "")
+        {{
+            {2}[] inArray1 = new {2}[ElementCount];
+            {2}[] inArray2 = new {2}[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }}
+
+        private void ValidateResult({2}[] left, {2}[] right, {2}[] result, [CallerMemberName] string method = "")
+        {{
+            if ({6})
+            {{
+                Succeeded = false;
+            }}
+            else
+            {{
+                for (var i = 1; i < left.Length; i++)
+                {{
+                    if ({7})
+                    {{
+                        Succeeded = false;
+                        break;
+                    }}
+                }}
+            }}
+
+            if (!Succeeded)
+            {{
+                Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{1})}}<{2}>: {{method}} failed:");
+                Console.WriteLine($"    left: ({{string.Join(", ", left)}})");
+                Console.WriteLine($"   right: ({{string.Join(", ", right)}})");
+                Console.WriteLine($"  result: ({{string.Join(", ", result)}})");
+                Console.WriteLine();
+            }}
+        }}
+    }}
+}}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable.cs b/tests/src/JIT/HardwareIntrinsics/X86/Shared/SimpleBinOpTest_DataTable.cs
new file mode 100644 (file)
index 0000000..896cbc2
--- /dev/null
@@ -0,0 +1,45 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public unsafe struct SimpleBinaryOpTest__DataTable<T> : IDisposable where T : struct
+    {
+        private GCHandle inHandle1;
+        private GCHandle inHandle2;
+        private GCHandle outHandle;
+
+        public T[] inArray1;
+        public T[] inArray2;
+        public T[] outArray;
+
+        public SimpleBinaryOpTest__DataTable(T[] inArray1, T[] inArray2, T[] outArray)
+        {
+            this.inArray1 = inArray1;
+            this.inArray2 = inArray2;
+            this.outArray = outArray;
+
+            this.inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned);
+            this.inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned);
+            this.outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned);
+        }
+
+        public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer();
+        public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer();
+        public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer();
+
+        public void Dispose()
+        {
+            inHandle1.Free();
+            inHandle2.Free();
+            outHandle.Free();
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Byte.cs
new file mode 100644 (file)
index 0000000..c5aaaaa
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddByte()
+        {
+            var test = new SimpleBinaryOpTest__AddByte();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddByte
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(Byte);
+
+        private static Byte[] _data1 = new Byte[ElementCount];
+        private static Byte[] _data2 = new Byte[ElementCount];
+
+        private static Vector128<Byte> _clsVar1;
+        private static Vector128<Byte> _clsVar2;
+
+        private Vector128<Byte> _fld1;
+        private Vector128<Byte> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Byte> _dataTable;
+
+        static SimpleBinaryOpTest__AddByte()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddByte()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Byte>(_data1, _data2, new Byte[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), 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<Byte>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddByte();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, Byte[] result, [CallerMemberName] string method = "")
+        {
+            Byte[] inArray1 = new Byte[ElementCount];
+            Byte[] inArray2 = new Byte[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "")
+        {
+            if ((byte)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((byte)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<Byte>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Double.cs
new file mode 100644 (file)
index 0000000..7340087
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddDouble()
+        {
+            var test = new SimpleBinaryOpTest__AddDouble();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddDouble
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(Double);
+
+        private static Double[] _data1 = new Double[ElementCount];
+        private static Double[] _data2 = new Double[ElementCount];
+
+        private static Vector128<Double> _clsVar1;
+        private static Vector128<Double> _clsVar2;
+
+        private Vector128<Double> _fld1;
+        private Vector128<Double> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Double> _dataTable;
+
+        static SimpleBinaryOpTest__AddDouble()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar1), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _clsVar2), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddDouble()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld1), ref Unsafe.As<Double, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Double>, byte>(ref _fld2), ref Unsafe.As<Double, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (double)(random.NextDouble()); _data2[i] = (double)(random.NextDouble()); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Double>(_data1, _data2, new Double[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Double>), typeof(Vector128<Double>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Double>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<Double>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Double>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddDouble();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Double> left, Vector128<Double> right, Double[] result, [CallerMemberName] string method = "")
+        {
+            Double[] inArray1 = new Double[ElementCount];
+            Double[] inArray2 = new Double[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(Double[] left, Double[] right, Double[] result, [CallerMemberName] string method = "")
+        {
+            if (BitConverter.DoubleToInt64Bits(left[0] + right[0]) != BitConverter.DoubleToInt64Bits(result[0]))
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if (BitConverter.DoubleToInt64Bits(left[i] + right[i]) != BitConverter.DoubleToInt64Bits(result[i]))
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<Double>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int16.cs
new file mode 100644 (file)
index 0000000..6612bf5
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddInt16()
+        {
+            var test = new SimpleBinaryOpTest__AddInt16();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddInt16
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(Int16);
+
+        private static Int16[] _data1 = new Int16[ElementCount];
+        private static Int16[] _data2 = new Int16[ElementCount];
+
+        private static Vector128<Int16> _clsVar1;
+        private static Vector128<Int16> _clsVar2;
+
+        private Vector128<Int16> _fld1;
+        private Vector128<Int16> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Int16> _dataTable;
+
+        static SimpleBinaryOpTest__AddInt16()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddInt16()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Int16>(_data1, _data2, new Int16[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), 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<Int16>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddInt16();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, Int16[] result, [CallerMemberName] string method = "")
+        {
+            Int16[] inArray1 = new Int16[ElementCount];
+            Int16[] inArray2 = new Int16[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "")
+        {
+            if ((short)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((short)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<Int16>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int32.cs
new file mode 100644 (file)
index 0000000..0318172
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddInt32()
+        {
+            var test = new SimpleBinaryOpTest__AddInt32();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddInt32
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(Int32);
+
+        private static Int32[] _data1 = new Int32[ElementCount];
+        private static Int32[] _data2 = new Int32[ElementCount];
+
+        private static Vector128<Int32> _clsVar1;
+        private static Vector128<Int32> _clsVar2;
+
+        private Vector128<Int32> _fld1;
+        private Vector128<Int32> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Int32> _dataTable;
+
+        static SimpleBinaryOpTest__AddInt32()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddInt32()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Int32>(_data1, _data2, new Int32[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddInt32();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Int32> left, Vector128<Int32> right, Int32[] result, [CallerMemberName] string method = "")
+        {
+            Int32[] inArray1 = new Int32[ElementCount];
+            Int32[] inArray2 = new Int32[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "")
+        {
+            if ((int)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((int)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<Int32>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.Int64.cs
new file mode 100644 (file)
index 0000000..9d168f0
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddInt64()
+        {
+            var test = new SimpleBinaryOpTest__AddInt64();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddInt64
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(Int64);
+
+        private static Int64[] _data1 = new Int64[ElementCount];
+        private static Int64[] _data2 = new Int64[ElementCount];
+
+        private static Vector128<Int64> _clsVar1;
+        private static Vector128<Int64> _clsVar2;
+
+        private Vector128<Int64> _fld1;
+        private Vector128<Int64> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<Int64> _dataTable;
+
+        static SimpleBinaryOpTest__AddInt64()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddInt64()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<Int64>(_data1, _data2, new Int64[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddInt64();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<Int64> left, Vector128<Int64> right, Int64[] result, [CallerMemberName] string method = "")
+        {
+            Int64[] inArray1 = new Int64[ElementCount];
+            Int64[] inArray2 = new Int64[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "")
+        {
+            if ((long)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((long)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<Int64>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.SByte.cs
new file mode 100644 (file)
index 0000000..fe37a9a
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddSByte()
+        {
+            var test = new SimpleBinaryOpTest__AddSByte();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddSByte
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(SByte);
+
+        private static SByte[] _data1 = new SByte[ElementCount];
+        private static SByte[] _data2 = new SByte[ElementCount];
+
+        private static Vector128<SByte> _clsVar1;
+        private static Vector128<SByte> _clsVar2;
+
+        private Vector128<SByte> _fld1;
+        private Vector128<SByte> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<SByte> _dataTable;
+
+        static SimpleBinaryOpTest__AddSByte()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar1), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _clsVar2), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddSByte()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld1), ref Unsafe.As<SByte, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<SByte>, byte>(ref _fld2), ref Unsafe.As<SByte, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<SByte>(_data1, _data2, new SByte[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<SByte>), typeof(Vector128<SByte>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<SByte>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<SByte>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddSByte();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<SByte> left, Vector128<SByte> right, SByte[] result, [CallerMemberName] string method = "")
+        {
+            SByte[] inArray1 = new SByte[ElementCount];
+            SByte[] inArray2 = new SByte[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "")
+        {
+            if ((sbyte)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((sbyte)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<SByte>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt16.cs
new file mode 100644 (file)
index 0000000..ea6da58
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddUInt16()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt16();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddUInt16
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(UInt16);
+
+        private static UInt16[] _data1 = new UInt16[ElementCount];
+        private static UInt16[] _data2 = new UInt16[ElementCount];
+
+        private static Vector128<UInt16> _clsVar1;
+        private static Vector128<UInt16> _clsVar2;
+
+        private Vector128<UInt16> _fld1;
+        private Vector128<UInt16> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<UInt16> _dataTable;
+
+        static SimpleBinaryOpTest__AddUInt16()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddUInt16()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<UInt16>(_data1, _data2, new UInt16[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt16();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<UInt16> left, Vector128<UInt16> right, UInt16[] result, [CallerMemberName] string method = "")
+        {
+            UInt16[] inArray1 = new UInt16[ElementCount];
+            UInt16[] inArray2 = new UInt16[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "")
+        {
+            if ((ushort)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((ushort)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<UInt16>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt32.cs
new file mode 100644 (file)
index 0000000..4ad0bff
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddUInt32()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt32();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddUInt32
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(UInt32);
+
+        private static UInt32[] _data1 = new UInt32[ElementCount];
+        private static UInt32[] _data2 = new UInt32[ElementCount];
+
+        private static Vector128<UInt32> _clsVar1;
+        private static Vector128<UInt32> _clsVar2;
+
+        private Vector128<UInt32> _fld1;
+        private Vector128<UInt32> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<UInt32> _dataTable;
+
+        static SimpleBinaryOpTest__AddUInt32()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddUInt32()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<UInt32>(_data1, _data2, new UInt32[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt32();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<UInt32> left, Vector128<UInt32> right, UInt32[] result, [CallerMemberName] string method = "")
+        {
+            UInt32[] inArray1 = new UInt32[ElementCount];
+            UInt32[] inArray2 = new UInt32[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "")
+        {
+            if ((uint)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((uint)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<UInt32>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.UInt64.cs
new file mode 100644 (file)
index 0000000..96ed081
--- /dev/null
@@ -0,0 +1,209 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        private static void AddUInt64()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt64();
+
+            if (test.IsSupported)
+            {
+                // Validates basic functionality works
+                test.RunBasicScenario();
+
+                // Validates calling via reflection works
+                test.RunReflectionScenario();
+
+                // Validates passing a static member works
+                test.RunClsVarScenario();
+
+                // Validates passing a local works
+                test.RunLclVarScenario();
+
+                // Validates passing the field of a local works
+                test.RunLclFldScenario();
+
+                // Validates passing an instance member works
+                test.RunFldScenario();
+            }
+            else
+            {
+                // Validates we throw on unsupported hardware
+                test.RunUnsupportedScenario();
+            }
+
+            if (!test.Succeeded)
+            {
+                throw new Exception("One or more scenarios did not complete as expected.");
+            }
+        }
+    }
+
+    public sealed unsafe class SimpleBinaryOpTest__AddUInt64
+    {
+        private const int VectorSize = 16;
+        private const int ElementCount = VectorSize / sizeof(UInt64);
+
+        private static UInt64[] _data1 = new UInt64[ElementCount];
+        private static UInt64[] _data2 = new UInt64[ElementCount];
+
+        private static Vector128<UInt64> _clsVar1;
+        private static Vector128<UInt64> _clsVar2;
+
+        private Vector128<UInt64> _fld1;
+        private Vector128<UInt64> _fld2;
+
+        private SimpleBinaryOpTest__DataTable<UInt64> _dataTable;
+
+        static SimpleBinaryOpTest__AddUInt64()
+        {
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize);
+        }
+
+        public SimpleBinaryOpTest__AddUInt64()
+        {
+            Succeeded = true;
+
+            var random = new Random();
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); }
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), VectorSize);
+            Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), VectorSize);
+
+            for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); }
+            _dataTable = new SimpleBinaryOpTest__DataTable<UInt64>(_data1, _data2, new UInt64[ElementCount]);
+        }
+
+        public bool IsSupported => Sse2.IsSupported;
+
+        public bool Succeeded { get; set; }
+
+        public void RunBasicScenario()
+        {
+            var result = Sse2.Add(
+                Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr),
+                Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr)
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunReflectionScenario()
+        {
+            var result = typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) })
+                                     .Invoke(null, new object[] {
+                                        Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr),
+                                        Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr)
+                                     });
+
+            Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result));
+            ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray);
+        }
+
+        public void RunClsVarScenario()
+        {
+            var result = Sse2.Add(
+                _clsVar1,
+                _clsVar2
+            );
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray);
+        }
+
+        public void RunLclVarScenario()
+        {
+            var left = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr);
+            var right = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr);
+            var result = Sse2.Add(left, right);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(left, right, _dataTable.outArray);
+        }
+
+        public void RunLclFldScenario()
+        {
+            var test = new SimpleBinaryOpTest__AddUInt64();
+            var result = Sse2.Add(test._fld1, test._fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(test._fld1, test._fld2, _dataTable.outArray);
+        }
+
+        public void RunFldScenario()
+        {
+            var result = Sse2.Add(_fld1, _fld2);
+
+            Unsafe.Write(_dataTable.outArrayPtr, result);
+            ValidateResult(_fld1, _fld2, _dataTable.outArray);
+        }
+
+        public void RunUnsupportedScenario()
+        {
+            Succeeded = false;
+
+            try
+            {
+                RunBasicScenario();
+            }
+            catch (PlatformNotSupportedException)
+            {
+                Succeeded = true;
+            }
+        }
+
+        private void ValidateResult(Vector128<UInt64> left, Vector128<UInt64> right, UInt64[] result, [CallerMemberName] string method = "")
+        {
+            UInt64[] inArray1 = new UInt64[ElementCount];
+            UInt64[] inArray2 = new UInt64[ElementCount];
+
+            Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left);
+            Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right);
+
+            ValidateResult(inArray1, inArray2, result, method);
+        }
+
+        private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "")
+        {
+            if ((ulong)(left[0] + right[0]) != result[0])
+            {
+                Succeeded = false;
+            }
+            else
+            {
+                for (var i = 1; i < left.Length; i++)
+                {
+                    if ((ulong)(left[i] + right[i]) != result[i])
+                    {
+                        Succeeded = false;
+                        break;
+                    }
+                }
+            }
+
+            if (!Succeeded)
+            {
+                Console.WriteLine($"{nameof(Sse2)}.{nameof(Sse2.Add)}<UInt64>: {method} failed:");
+                Console.WriteLine($"    left: ({string.Join(", ", left)})");
+                Console.WriteLine($"   right: ({string.Join(", ", right)})");
+                Console.WriteLine($"  result: ({string.Join(", ", result)})");
+                Console.WriteLine();
+            }
+        }
+    }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Add.cs
deleted file mode 100644 (file)
index 3d4458c..0000000
+++ /dev/null
@@ -1,356 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-// See the LICENSE file in the project root for more information.
-//
-
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Runtime.Intrinsics.X86;
-using System.Runtime.Intrinsics;
-
-namespace IntelHardwareIntrinsicTest
-{
-    class Program
-    {
-        const int Pass = 100;
-        const int Fail = 0;
-
-        static unsafe int Main(string[] args)
-        {
-            int testResult = Pass;
-
-            if (Sse2.IsSupported)
-            {
-                using (TestTable<double> doubleTable = new TestTable<double>(new double[2] { 1, -5 }, new double[2] { 22, -1 }, new double[2]))
-                using (TestTable<int> intTable = new TestTable<int>(new int[4] { 1, -5, 100, 0 }, new int[4] { 22, -1, -50, 0 }, new int[4]))
-                using (TestTable<long> longTable = new TestTable<long>(new long[2] { 1, -5 }, new long[2] { 22, -1 }, new long[2]))
-                using (TestTable<uint> uintTable = new TestTable<uint>(new uint[4] { 1, 5, 100, 0 }, new uint[4] { 22, 1, 50, 0 }, new uint[4]))
-                using (TestTable<ulong> ulongTable = new TestTable<ulong>(new ulong[2] { 1, 5 }, new ulong[2] { 22, 1 }, new ulong[2]))
-                using (TestTable<short> shortTable = new TestTable<short>(new short[8] { 1, -5, 100, 0, 1, -5, 100, 0 }, new short[8] { 22, -1, -50, 0, 22, -1, -50, 0 }, new short[8]))
-                using (TestTable<ushort> ushortTable = new TestTable<ushort>(new ushort[8] { 1, 5, 100, 0, 1, 5, 100, 0 }, new ushort[8] { 22, 1, 50, 0, 22, 1, 50, 0 }, new ushort[8]))
-                using (TestTable<sbyte> sbyteTable = new TestTable<sbyte>(new sbyte[16] { 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0, 1, -5, 100, 0 }, new sbyte[16] { 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0, 22, -1, -50, 0 }, new sbyte[16]))
-                using (TestTable<byte> byteTable = new TestTable<byte>(new byte[16] { 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0, 1, 5, 100, 0 }, new byte[16] { 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0, 22, 1, 50, 0 }, new byte[16]))
-                {
-                    var vd1 = Unsafe.Read<Vector128<double>>(doubleTable.inArray1Ptr);
-                    var vd2 = Unsafe.Read<Vector128<double>>(doubleTable.inArray2Ptr);
-                    var vd3 = Sse2.Add(vd1, vd2);
-                    Unsafe.Write(doubleTable.outArrayPtr, vd3);
-
-                    if (!doubleTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on double:");
-                        foreach (var item in doubleTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vd3 = (Vector128<double>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vd1.GetType(), vd2.GetType() }).Invoke(null, new object[] { vd1, vd2 });
-                    Unsafe.Write(doubleTable.outArrayPtr, vd3);
-
-                    if (!doubleTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on double:");
-                        foreach (var item in doubleTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vi1 = Unsafe.Read<Vector128<int>>(intTable.inArray1Ptr);
-                    var vi2 = Unsafe.Read<Vector128<int>>(intTable.inArray2Ptr);
-                    var vi3 = Sse2.Add(vi1, vi2);
-                    Unsafe.Write(intTable.outArrayPtr, vi3);
-
-                    if (!intTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on int:");
-                        foreach (var item in intTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vi3 = (Vector128<int>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vi1.GetType(), vi2.GetType() }).Invoke(null, new object[] { vi1, vi2 });
-                    Unsafe.Write(intTable.outArrayPtr, vi3);
-
-                    if (!intTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on int:");
-                        foreach (var item in intTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vl1 = Unsafe.Read<Vector128<long>>(longTable.inArray1Ptr);
-                    var vl2 = Unsafe.Read<Vector128<long>>(longTable.inArray2Ptr);
-                    var vl3 = Sse2.Add(vl1, vl2);
-                    Unsafe.Write(longTable.outArrayPtr, vl3);
-
-                    if (!longTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on long:");
-                        foreach (var item in longTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vl3 = (Vector128<long>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vl1.GetType(), vl2.GetType() }).Invoke(null, new object[] { vl1, vl2 });
-                    Unsafe.Write(longTable.outArrayPtr, vl3);
-
-                    if (!longTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on long:");
-                        foreach (var item in longTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vui1 = Unsafe.Read<Vector128<uint>>(uintTable.inArray1Ptr);
-                    var vui2 = Unsafe.Read<Vector128<uint>>(uintTable.inArray2Ptr);
-                    var vui3 = Sse2.Add(vui1, vui2);
-                    Unsafe.Write(uintTable.outArrayPtr, vui3);
-
-                    if (!uintTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on uint:");
-                        foreach (var item in uintTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vui3 = (Vector128<uint>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vui1.GetType(), vui2.GetType() }).Invoke(null, new object[] { vui1, vui2 });
-                    Unsafe.Write(uintTable.outArrayPtr, vui3);
-
-                    if (!uintTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on uint:");
-                        foreach (var item in uintTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vul1 = Unsafe.Read<Vector128<ulong>>(ulongTable.inArray1Ptr);
-                    var vul2 = Unsafe.Read<Vector128<ulong>>(ulongTable.inArray2Ptr);
-                    var vul3 = Sse2.Add(vul1, vul2);
-                    Unsafe.Write(ulongTable.outArrayPtr, vul3);
-
-                    if (!ulongTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on ulong:");
-                        foreach (var item in ulongTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vul3 = (Vector128<ulong>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vul1.GetType(), vul2.GetType() }).Invoke(null, new object[] { vul1, vul2 });
-                    Unsafe.Write(ulongTable.outArrayPtr, vul3);
-
-                    if (!ulongTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on ulong:");
-                        foreach (var item in ulongTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vs1 = Unsafe.Read<Vector128<short>>(shortTable.inArray1Ptr);
-                    var vs2 = Unsafe.Read<Vector128<short>>(shortTable.inArray2Ptr);
-                    var vs3 = Sse2.Add(vs1, vs2);
-                    Unsafe.Write(shortTable.outArrayPtr, vs3);
-
-                    if (!shortTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on short:");
-                        foreach (var item in shortTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vs3 = (Vector128<short>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vs1.GetType(), vs2.GetType() }).Invoke(null, new object[] { vs1, vs2 });
-                    Unsafe.Write(shortTable.outArrayPtr, vs3);
-
-                    if (!shortTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on short:");
-                        foreach (var item in shortTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vus1 = Unsafe.Read<Vector128<ushort>>(ushortTable.inArray1Ptr);
-                    var vus2 = Unsafe.Read<Vector128<ushort>>(ushortTable.inArray2Ptr);
-                    var vus3 = Sse2.Add(vus1, vus2);
-                    Unsafe.Write(ushortTable.outArrayPtr, vus3);
-
-                    if (!ushortTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on ushort:");
-                        foreach (var item in ushortTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vus3 = (Vector128<ushort>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vus1.GetType(), vus2.GetType() }).Invoke(null, new object[] { vus1, vus2 });
-                    Unsafe.Write(ushortTable.outArrayPtr, vus3);
-
-                    if (!ushortTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on ushort:");
-                        foreach (var item in ushortTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vsb1 = Unsafe.Read<Vector128<sbyte>>(sbyteTable.inArray1Ptr);
-                    var vsb2 = Unsafe.Read<Vector128<sbyte>>(sbyteTable.inArray2Ptr);
-                    var vsb3 = Sse2.Add(vsb1, vsb2);
-                    Unsafe.Write(sbyteTable.outArrayPtr, vsb3);
-
-                    if (!sbyteTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on sbyte:");
-                        foreach (var item in sbyteTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vsb3 = (Vector128<sbyte>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vsb1.GetType(), vsb2.GetType() }).Invoke(null, new object[] { vsb1, vsb2 });
-                    Unsafe.Write(sbyteTable.outArrayPtr, vsb3);
-
-                    if (!sbyteTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on sbyte:");
-                        foreach (var item in sbyteTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    var vb1 = Unsafe.Read<Vector128<byte>>(byteTable.inArray1Ptr);
-                    var vb2 = Unsafe.Read<Vector128<byte>>(byteTable.inArray2Ptr);
-                    var vb3 = Sse2.Add(vb1, vb2);
-                    Unsafe.Write(byteTable.outArrayPtr, vb3);
-
-                    if (!byteTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed on byte:");
-                        foreach (var item in byteTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-
-                    vb3 = (Vector128<byte>)typeof(Sse2).GetMethod(nameof(Sse2.Add), new Type[] { vb1.GetType(), vb2.GetType() }).Invoke(null, new object[] { vb1, vb2 });
-                    Unsafe.Write(byteTable.outArrayPtr, vb3);
-
-                    if (!byteTable.CheckResult((x, y, z) => x + y == z))
-                    {
-                        Console.WriteLine("SSE2 Add failed via reflection on byte:");
-                        foreach (var item in byteTable.outArray)
-                        {
-                            Console.Write(item + ", ");
-                        }
-                        Console.WriteLine();
-                        testResult = Fail;
-                    }
-                
-                }
-            }
-
-
-            return testResult;
-        }
-
-        public unsafe struct TestTable<T> : IDisposable where T : struct
-        {
-            public T[] inArray1;
-            public T[] inArray2;
-            public T[] outArray;
-
-            public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer();
-            public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer();
-            public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer();
-
-            GCHandle inHandle1;
-            GCHandle inHandle2;
-            GCHandle outHandle;
-            public TestTable(T[] a, T[] b, T[] c)
-            {
-                this.inArray1 = a;
-                this.inArray2 = b;
-                this.outArray = c;
-
-                inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned);
-                inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned);
-                outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned);
-            }
-            public bool CheckResult(Func<T, T, T, bool> check)
-            {
-                for (int i = 0; i < inArray1.Length; i++)
-                {
-                    if (!check(inArray1[i], inArray2[i], outArray[i]))
-                    {
-                        return false;
-                    }
-                }
-                return true;
-            }
-
-            public void Dispose()
-            {
-                inHandle1.Free();
-                inHandle2.Free();
-                outHandle.Free();
-            }
-        }
-
-    }
-}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs
new file mode 100644 (file)
index 0000000..6994fe6
--- /dev/null
@@ -0,0 +1,27 @@
+// 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.Collections.Generic;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+    public static partial class Program
+    {
+        static Program()
+        {
+            TestList = new Dictionary<string, Action>() {
+                ["Add.Double"] = AddDouble,
+                ["Add.Byte"] = AddByte,
+                ["Add.Int16"] = AddInt16,
+                ["Add.Int32"] = AddInt32,
+                ["Add.Int64"] = AddInt64,
+                ["Add.SByte"] = AddSByte,
+                ["Add.UInt16"] = AddUInt16,
+                ["Add.UInt32"] = AddUInt32,
+                ["Add.UInt64"] = AddUInt64,
+            };
+        }
+    }
+}
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Add.cs" />
+    <Compile Include="Add.Byte.cs" />
+    <Compile Include="Add.Double.cs" />
+    <Compile Include="Add.Int16.cs" />
+    <Compile Include="Add.Int32.cs" />
+    <Compile Include="Add.Int64.cs" />
+    <Compile Include="Add.SByte.cs" />
+    <Compile Include="Add.UInt16.cs" />
+    <Compile Include="Add.UInt32.cs" />
+    <Compile Include="Add.UInt64.cs" />
+    <Compile Include="Program.Sse2.cs" />
+    <Compile Include="..\Shared\Program.cs" />
+    <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" />
   </ItemGroup>
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
   <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
     <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
   </ItemGroup>
   <ItemGroup>
-    <Compile Include="Add.cs" />
+    <Compile Include="Add.Byte.cs" />
+    <Compile Include="Add.Double.cs" />
+    <Compile Include="Add.Int16.cs" />
+    <Compile Include="Add.Int32.cs" />
+    <Compile Include="Add.Int64.cs" />
+    <Compile Include="Add.SByte.cs" />
+    <Compile Include="Add.UInt16.cs" />
+    <Compile Include="Add.UInt32.cs" />
+    <Compile Include="Add.UInt64.cs" />
+    <Compile Include="Program.Sse2.cs" />
+    <Compile Include="..\Shared\Program.cs" />
+    <Compile Include="..\Shared\SimpleBinOpTest_DataTable.cs" />
   </ItemGroup>
   <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
   <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>