From 225391f8238914f224f6a67707753e14fe13ae85 Mon Sep 17 00:00:00 2001 From: Fei Peng Date: Thu, 27 Sep 2018 16:54:10 -0700 Subject: [PATCH] Re-enable hardware intrinsic tests --- tests/arm/Tests.lst | 16 + tests/arm64/Tests.lst | 16 + .../JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs | 131 +++++++ .../HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj | 33 ++ .../HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj | 33 ++ .../X86/Shared/GenerateTests.csx | 2 + .../X86/Sse2/MultiplyAddAdjacent.Int32.cs | 403 +++++++++++++++++++++ .../HardwareIntrinsics/X86/Sse2/Program.Sse2.cs | 2 + .../JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj | 2 + .../JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj | 2 + .../X86/Sse2/SumAbsoluteDifferences.UInt16.cs | 403 +++++++++++++++++++++ 11 files changed, 1043 insertions(+) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs diff --git a/tests/arm/Tests.lst b/tests/arm/Tests.lst index ee226c9..a5c162e 100644 --- a/tests/arm/Tests.lst +++ b/tests/arm/Tests.lst @@ -91100,6 +91100,14 @@ MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS;NEW;EXCLUDED HostStyle=0 +[Popcnt_r.cmd_11492] +RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_r\Popcnt_r.cmd +WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_r +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS;NEW;EXCLUDED +HostStyle=0 + [StoreLow_r.cmd_11493] RelativePath=JIT\HardwareIntrinsics\X86\Sse2\StoreLow_r\StoreLow_r.cmd WorkingDir=JIT\HardwareIntrinsics\X86\Sse2\StoreLow_r @@ -93340,6 +93348,14 @@ MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS;NEW;EXCLUDED HostStyle=0 +[Popcnt_ro.cmd_11829] +RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro\Popcnt_ro.cmd +WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS;NEW;EXCLUDED +HostStyle=0 + [MoveHighAndDuplicate_ro.cmd_11830] RelativePath=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro\MoveHighAndDuplicate_ro.cmd WorkingDir=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro diff --git a/tests/arm64/Tests.lst b/tests/arm64/Tests.lst index 9f12dfd..f30f524 100644 --- a/tests/arm64/Tests.lst +++ b/tests/arm64/Tests.lst @@ -93308,6 +93308,14 @@ MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS;NEW;EXCLUDED HostStyle=0 +[MultiplyHorizontalAdd_ro.cmd_12141] +RelativePath=JIT\HardwareIntrinsics\X86\Sse2\MultiplyHorizontalAdd_ro\MultiplyHorizontalAdd_ro.cmd +WorkingDir=JIT\HardwareIntrinsics\X86\Sse2\MultiplyHorizontalAdd_ro +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS;NEW;EXCLUDED +HostStyle=0 + [MoveHighToLow_r.cmd_12142] RelativePath=JIT\HardwareIntrinsics\X86\Sse\MoveHighToLow_r\MoveHighToLow_r.cmd WorkingDir=JIT\HardwareIntrinsics\X86\Sse\MoveHighToLow_r @@ -93332,6 +93340,14 @@ MaxAllowedDurationSeconds=600 Categories=EXPECTED_PASS;NEW;EXCLUDED HostStyle=0 +[Popcnt_ro.cmd_12145] +RelativePath=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro\Popcnt_ro.cmd +WorkingDir=JIT\HardwareIntrinsics\X86\Popcnt\Popcnt_ro +Expected=0 +MaxAllowedDurationSeconds=600 +Categories=EXPECTED_PASS;NEW;EXCLUDED +HostStyle=0 + [MoveHighAndDuplicate_ro.cmd_12146] RelativePath=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro\MoveHighAndDuplicate_ro.cmd WorkingDir=JIT\HardwareIntrinsics\X86\Sse3\MoveHighAndDuplicate_ro diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs new file mode 100644 index 0000000..e30a8ed --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt.cs @@ -0,0 +1,131 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. +// + +using System; +using System.Reflection; +using System.Runtime.Intrinsics.X86; + +namespace IntelHardwareIntrinsicTest +{ + class Program + { + const int Pass = 100; + const int Fail = 0; + + static int Main(string[] args) + { + ulong sl = 0; + ulong resl; + int testResult = Pass; + + if (!Popcnt.IsSupported || !Environment.Is64BitProcess) + { + try + { + resl = Popcnt.PopCount(sl); + Console.WriteLine("Intrinsic Popcnt.PopCount is called on non-supported hardware"); + Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported); + Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess); + testResult = Fail; + } + catch (PlatformNotSupportedException) + { + } + + try + { + resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl })); + Console.WriteLine("Intrinsic Popcnt.PopCount is called via reflection on non-supported hardware"); + Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported); + Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess); + testResult = Fail; + } + catch (TargetInvocationException e) when (e.InnerException is PlatformNotSupportedException) + { + } + } + + + if (Popcnt.IsSupported) + { + if (Environment.Is64BitProcess) + { + for (int i = 0; i < longPopcntTable.Length; i++) + { + sl = longPopcntTable[i].s; + + resl = Popcnt.PopCount(sl); + if (resl != longPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, sl, longPopcntTable[i].res, resl); + testResult = Fail; + } + + resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl })); + if (resl != longPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection", + i, sl, longPopcntTable[i].res, resl); + testResult = Fail; + } + } + } + + uint si; + uint resi; + for (int i = 0; i < intPopcntTable.Length; i++) + { + si = intPopcntTable[i].s; + + resi = Popcnt.PopCount(si); + if (resi != intPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}", + i, si, intPopcntTable[i].res, resi); + testResult = Fail; + } + + resi = Convert.ToUInt32(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { si.GetType() }).Invoke(null, new object[] { si })); + if (resi != intPopcntTable[i].res) + { + Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection", + i, si, intPopcntTable[i].res, resi); + testResult = Fail; + } + } + } + + return testResult; + } + + public struct POPCNT where T : struct where U : struct + { + public T s; + public U res; + public POPCNT(T a, U r) + { + this.s = a; + this.res = r; + } + } + + public static POPCNT[] longPopcntTable = { + new POPCNT(0x0000000000000000UL, 0UL), + new POPCNT(0x0000000000000001UL, 1UL), + new POPCNT(0xffffffffffffffffUL, 64UL), + new POPCNT(0x8000000000000000UL, 1UL), + new POPCNT(0x00050000000f423fUL, 14UL) + }; + + public static POPCNT[] intPopcntTable = { + new POPCNT(0x00000000U, 0U), + new POPCNT(0x00000001U, 1U), + new POPCNT(0xffffffffU, 32U), + new POPCNT(0x80000000U, 1U), + new POPCNT(0x0005423fU, 10U) + }; + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj new file mode 100644 index 0000000..e32ab7a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_r.csproj @@ -0,0 +1,33 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + Embedded + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj new file mode 100644 index 0000000..a53bf1b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Popcnt/Popcnt_ro.csproj @@ -0,0 +1,33 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + + + + + + + False + + + + Embedded + True + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 469dddb..d99bd66 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -194,6 +194,7 @@ private static readonly (string templateFileName, Dictionary tem ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Math.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyAddAdjacent", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue)", ["ValidateRemainingResults"] = "result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue)"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "(BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "(BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "(byte)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(byte)(left[i] | right[i]) != result[i]"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "(short)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(short)(left[i] | right[i]) != result[i]"}), @@ -273,6 +274,7 @@ private static readonly (string templateFileName, Dictionary tem ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])", ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])", ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}), + ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SumAbsoluteDifferences", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7])", ["ValidateRemainingResults"] = "result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15]))"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(left[1])", ["ValidateRemainingResults"] = "(i % 2 == 0) ? BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i/2+1]) : BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(right[(i - 1)/2 + 1])"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]", ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}), ("SimpleBinOpTest.template", new Dictionary { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]", ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}), diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs new file mode 100644 index 0000000..49dd651 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/MultiplyAddAdjacent.Int32.cs @@ -0,0 +1,403 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void MultiplyAddAdjacentInt32() + { + var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__MultiplyAddAdjacentInt32 + { + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyAddAdjacentInt32 testClass) + { + var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Int16); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Int32); + + private static Int16[] _data1 = new Int16[Op1ElementCount]; + private static Int16[] _data2 = new Int16[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__MultiplyAddAdjacentInt32() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__MultiplyAddAdjacentInt32() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Int32[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Sse2.MultiplyAddAdjacent( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse2.MultiplyAddAdjacent( + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse2.MultiplyAddAdjacent( + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse2.MultiplyAddAdjacent( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse2.MultiplyAddAdjacent(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.MultiplyAddAdjacent(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)); + var result = Sse2.MultiplyAddAdjacent(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32(); + var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[Op1ElementCount]; + Int16[] inArray2 = new Int16[Op2ElementCount]; + Int32[] outArray = new Int32[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue)) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue)) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.MultiplyAddAdjacent)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs index aacdaa3..8822656 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Program.Sse2.cs @@ -129,6 +129,7 @@ namespace JIT.HardwareIntrinsics.X86 ["MinScalar.Double"] = MinScalarDouble, ["Multiply.Double"] = MultiplyDouble, ["MultiplyScalar.Double"] = MultiplyScalarDouble, + ["MultiplyAddAdjacent.Int32"] = MultiplyAddAdjacentInt32, ["Or.Double"] = OrDouble, ["Or.Byte"] = OrByte, ["Or.Int16"] = OrInt16, @@ -208,6 +209,7 @@ namespace JIT.HardwareIntrinsics.X86 ["SubtractSaturate.Int16"] = SubtractSaturateInt16, ["SubtractSaturate.UInt16"] = SubtractSaturateUInt16, ["SubtractScalar.Double"] = SubtractScalarDouble, + ["SumAbsoluteDifferences.UInt16"] = SumAbsoluteDifferencesUInt16, ["UnpackHigh.Double"] = UnpackHighDouble, ["UnpackHigh.Int64"] = UnpackHighInt64, ["UnpackHigh.UInt64"] = UnpackHighUInt64, diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj index b9101fc..a864813 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_r.csproj @@ -144,6 +144,7 @@ + @@ -223,6 +224,7 @@ + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj index 563bc43..7b894da 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/Sse2_ro.csproj @@ -144,6 +144,7 @@ + @@ -224,6 +225,7 @@ + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs new file mode 100644 index 0000000..be18337 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse2/SumAbsoluteDifferences.UInt16.cs @@ -0,0 +1,403 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +/****************************************************************************** + * This file is auto-generated from a template file by the GenerateTests.csx * + * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make * + * changes, please update the corresponding template and run according to the * + * directions listed in the file. * + ******************************************************************************/ + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void SumAbsoluteDifferencesUInt16() + { + var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates basic functionality works, using Load + test.RunBasicScenario_Load(); + + // Validates basic functionality works, using LoadAligned + test.RunBasicScenario_LoadAligned(); + } + + // Validates calling via reflection works, using Unsafe.Read + test.RunReflectionScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates calling via reflection works, using Load + test.RunReflectionScenario_Load(); + + // Validates calling via reflection works, using LoadAligned + test.RunReflectionScenario_LoadAligned(); + } + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse2.IsSupported) + { + // Validates passing a local works, using Load + test.RunLclVarScenario_Load(); + + // Validates passing a local works, using LoadAligned + test.RunLclVarScenario_LoadAligned(); + } + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16 + { + private struct TestStruct + { + public Vector128 _fld1; + public Vector128 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16 testClass) + { + var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr); + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int Op2ElementCount = Unsafe.SizeOf>() / sizeof(Byte); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(UInt16); + + private static Byte[] _data1 = new Byte[Op1ElementCount]; + private static Byte[] _data2 = new Byte[Op2ElementCount]; + + private static Vector128 _clsVar1; + private static Vector128 _clsVar2; + + private Vector128 _fld1; + private Vector128 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); } + for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize); + } + + public bool IsSupported => Sse2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Sse2.SumAbsoluteDifferences( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse2.SumAbsoluteDifferences( + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse2.SumAbsoluteDifferences( + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128), typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)), + Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse2.SumAbsoluteDifferences( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Sse2.SumAbsoluteDifferences(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.SumAbsoluteDifferences(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)); + var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr)); + var result = Sse2.SumAbsoluteDifferences(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16(); + var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + Succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector128 left, Vector128 right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), left); + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray2[0]), right); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[Op1ElementCount]; + Byte[] inArray2 = new Byte[Op2ElementCount]; + UInt16[] outArray = new UInt16[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(left), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray2[0]), ref Unsafe.AsRef(right), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, inArray2, outArray, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if (result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7])) + { + Succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15]))) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.SumAbsoluteDifferences)}(Vector128, Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})"); + TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + } + } + } +} -- 2.7.4