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
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
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
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
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+//
+
+using System;
+using System.Reflection;
+using System.Runtime.Intrinsics.X86;
+
+namespace IntelHardwareIntrinsicTest
+{
+ class Program
+ {
+ const int Pass = 100;
+ const int Fail = 0;
+
+ static int Main(string[] args)
+ {
+ ulong sl = 0;
+ ulong resl;
+ int testResult = Pass;
+
+ if (!Popcnt.IsSupported || !Environment.Is64BitProcess)
+ {
+ try
+ {
+ resl = Popcnt.PopCount(sl);
+ Console.WriteLine("Intrinsic Popcnt.PopCount is called on non-supported hardware");
+ Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported);
+ Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess);
+ testResult = Fail;
+ }
+ catch (PlatformNotSupportedException)
+ {
+ }
+
+ try
+ {
+ resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl }));
+ Console.WriteLine("Intrinsic Popcnt.PopCount is called via reflection on non-supported hardware");
+ Console.WriteLine("Popcnt.IsSupported " + Popcnt.IsSupported);
+ Console.WriteLine("Environment.Is64BitProcess " + Environment.Is64BitProcess);
+ testResult = Fail;
+ }
+ catch (TargetInvocationException e) when (e.InnerException is PlatformNotSupportedException)
+ {
+ }
+ }
+
+
+ if (Popcnt.IsSupported)
+ {
+ if (Environment.Is64BitProcess)
+ {
+ for (int i = 0; i < longPopcntTable.Length; i++)
+ {
+ sl = longPopcntTable[i].s;
+
+ resl = Popcnt.PopCount(sl);
+ if (resl != longPopcntTable[i].res)
+ {
+ Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}",
+ i, sl, longPopcntTable[i].res, resl);
+ testResult = Fail;
+ }
+
+ resl = Convert.ToUInt64(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { sl.GetType() }).Invoke(null, new object[] { sl }));
+ if (resl != longPopcntTable[i].res)
+ {
+ Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection",
+ i, sl, longPopcntTable[i].res, resl);
+ testResult = Fail;
+ }
+ }
+ }
+
+ uint si;
+ uint resi;
+ for (int i = 0; i < intPopcntTable.Length; i++)
+ {
+ si = intPopcntTable[i].s;
+
+ resi = Popcnt.PopCount(si);
+ if (resi != intPopcntTable[i].res)
+ {
+ Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x}",
+ i, si, intPopcntTable[i].res, resi);
+ testResult = Fail;
+ }
+
+ resi = Convert.ToUInt32(typeof(Popcnt).GetMethod(nameof(Popcnt.PopCount), new Type[] { si.GetType() }).Invoke(null, new object[] { si }));
+ if (resi != intPopcntTable[i].res)
+ {
+ Console.WriteLine("{0}: Inputs: 0x{1,16:x} Expected: 0x{3,16:x} actual: 0x{4,16:x} - Reflection",
+ i, si, intPopcntTable[i].res, resi);
+ testResult = Fail;
+ }
+ }
+ }
+
+ return testResult;
+ }
+
+ public struct POPCNT<T, U> where T : struct where U : struct
+ {
+ public T s;
+ public U res;
+ public POPCNT(T a, U r)
+ {
+ this.s = a;
+ this.res = r;
+ }
+ }
+
+ public static POPCNT<ulong,ulong>[] longPopcntTable = {
+ new POPCNT<ulong,ulong>(0x0000000000000000UL, 0UL),
+ new POPCNT<ulong,ulong>(0x0000000000000001UL, 1UL),
+ new POPCNT<ulong,ulong>(0xffffffffffffffffUL, 64UL),
+ new POPCNT<ulong,ulong>(0x8000000000000000UL, 1UL),
+ new POPCNT<ulong,ulong>(0x00050000000f423fUL, 14UL)
+ };
+
+ public static POPCNT<uint,uint>[] intPopcntTable = {
+ new POPCNT<uint,uint>(0x00000000U, 0U),
+ new POPCNT<uint,uint>(0x00000001U, 1U),
+ new POPCNT<uint,uint>(0xffffffffU, 32U),
+ new POPCNT<uint,uint>(0x80000000U, 1U),
+ new POPCNT<uint,uint>(0x0005423fU, 10U)
+ };
+ }
+}
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType>Embedded</DebugType>
+ <Optimize></Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Popcnt.cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
--- /dev/null
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.props))\dir.props" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{95DFC527-4DC1-495E-97D7-E94EE1F7140D}</ProjectGuid>
+ <OutputType>Exe</OutputType>
+ <ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
+ <SolutionDir Condition="$(SolutionDir) == '' Or $(SolutionDir) == '*Undefined*'">..\..\</SolutionDir>
+ </PropertyGroup>
+ <!-- Default configurations to help VS understand the configurations -->
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' "></PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' " />
+ <ItemGroup>
+ <CodeAnalysisDependentAssemblyPaths Condition=" '$(VS100COMNTOOLS)' != '' " Include="$(VS100COMNTOOLS)..\IDE\PrivateAssemblies">
+ <Visible>False</Visible>
+ </CodeAnalysisDependentAssemblyPaths>
+ </ItemGroup>
+ <PropertyGroup>
+ <DebugType>Embedded</DebugType>
+ <Optimize>True</Optimize>
+ </PropertyGroup>
+ <ItemGroup>
+ <Service Include="{82A7F48D-3B50-4B1E-B82E-3ADA8210C358}" />
+ </ItemGroup>
+ <ItemGroup>
+ <Compile Include="Popcnt.cs" />
+ </ItemGroup>
+ <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), dir.targets))\dir.targets" />
+ <PropertyGroup Condition=" '$(MsBuildProjectDirOverride)' != '' "></PropertyGroup>
+</Project>
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MinScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(Math.Min(left[0], right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Multiply", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i] * right[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] * right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "MultiplyAddAdjacent", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int32", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue)", ["ValidateRemainingResults"] = "result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue)"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "(BitConverter.DoubleToInt64Bits(left[0]) | BitConverter.DoubleToInt64Bits(right[0])) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "(BitConverter.DoubleToInt64Bits(left[i]) | BitConverter.DoubleToInt64Bits(right[i])) != BitConverter.DoubleToInt64Bits(result[i])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Byte", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "(byte)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(byte)(left[i] | right[i]) != result[i]"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "Or", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "(short)(left[0] | right[0]) != result[0]", ["ValidateRemainingResults"] = "(short)(left[i] | right[i]) != result[i]"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt16()", ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])", ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractSaturate", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt16", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt16", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt16()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt16()", ["ValidateFirstResult"] = "Sse2Verify.SubtractSaturate(left[0], right[0], result[0])", ["ValidateRemainingResults"] = "Sse2Verify.SubtractSaturate(left[i], right[i], result[i])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SubtractScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(left[0] - right[0]) != BitConverter.DoubleToInt64Bits(result[0])", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(left[i]) != BitConverter.DoubleToInt64Bits(result[i])"}),
+ ("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "SumAbsoluteDifferences", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt16", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Byte", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Byte", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetByte()", ["NextValueOp2"] = "TestLibrary.Generator.GetByte()", ["ValidateFirstResult"] = "result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7])", ["ValidateRemainingResults"] = "result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15]))"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Double", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["NextValueOp2"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(left[1])", ["ValidateRemainingResults"] = "(i % 2 == 0) ? BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(left[i/2+1]) : BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(right[(i - 1)/2 + 1])"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "Int64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "Int64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]", ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}),
("SimpleBinOpTest.template", new Dictionary<string, string> { ["Isa"] = "Sse2", ["LoadIsa"] = "Sse2", ["Method"] = "UnpackHigh", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] = "Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "result[0] != left[1] || result[1] != right[1]", ["ValidateRemainingResults"] = "(i % 2 == 0) ? result[i] != left[i/2 + 1] : result[i] != right[(i - 1)/2 + 1]"}),
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void MultiplyAddAdjacentInt32()
+ {
+ var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__MultiplyAddAdjacentInt32
+ {
+ private struct TestStruct
+ {
+ public Vector128<Int16> _fld1;
+ public Vector128<Int16> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref testStruct._fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref testStruct._fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyAddAdjacentInt32 testClass)
+ {
+ var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+
+ private static Int16[] _data1 = new Int16[Op1ElementCount];
+ private static Int16[] _data2 = new Int16[Op2ElementCount];
+
+ private static Vector128<Int16> _clsVar1;
+ private static Vector128<Int16> _clsVar2;
+
+ private Vector128<Int16> _fld1;
+ private Vector128<Int16> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<Int32, Int16, Int16> _dataTable;
+
+ static SimpleBinaryOpTest__MultiplyAddAdjacentInt32()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ }
+
+ public SimpleBinaryOpTest__MultiplyAddAdjacentInt32()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld1), ref Unsafe.As<Int16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld2), ref Unsafe.As<Int16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt16(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt16(); }
+ _dataTable = new SimpleBinaryOpTest__DataTable<Int32, Int16, Int16>(_data1, _data2, new Int32[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse2.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse2.MultiplyAddAdjacent(
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse2.MultiplyAddAdjacent(
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse2.MultiplyAddAdjacent(
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.MultiplyAddAdjacent), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse2.MultiplyAddAdjacent(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr);
+ var result = Sse2.MultiplyAddAdjacent(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr));
+ var result = Sse2.MultiplyAddAdjacent(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr));
+ var result = Sse2.MultiplyAddAdjacent(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__MultiplyAddAdjacentInt32();
+ var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse2.MultiplyAddAdjacent(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse2.MultiplyAddAdjacent(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ Succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ Succeeded = true;
+ }
+ }
+
+ private void ValidateResult(Vector128<Int16> left, Vector128<Int16> right, void* result, [CallerMemberName] string method = "")
+ {
+ Int16[] inArray1 = new Int16[Op1ElementCount];
+ Int16[] inArray2 = new Int16[Op2ElementCount];
+ Int32[] outArray = new Int32[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Int16[] inArray1 = new Int16[Op1ElementCount];
+ Int16[] inArray2 = new Int16[Op2ElementCount];
+ Int32[] outArray = new Int32[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Int16[] left, Int16[] right, Int32[] result, [CallerMemberName] string method = "")
+ {
+ if (result[0] != Math.Clamp(((right[1] * left[1]) + (right[0] * left[0])), int.MinValue, int.MaxValue))
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != Math.Clamp(((right[(i * 2) + 1] * left[(i * 2) + 1]) + (right[i * 2] * left[i * 2])), int.MinValue, int.MaxValue))
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.MultiplyAddAdjacent)}<Int32>(Vector128<Int16>, Vector128<Int16>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
["MinScalar.Double"] = MinScalarDouble,
["Multiply.Double"] = MultiplyDouble,
["MultiplyScalar.Double"] = MultiplyScalarDouble,
+ ["MultiplyAddAdjacent.Int32"] = MultiplyAddAdjacentInt32,
["Or.Double"] = OrDouble,
["Or.Byte"] = OrByte,
["Or.Int16"] = OrInt16,
["SubtractSaturate.Int16"] = SubtractSaturateInt16,
["SubtractSaturate.UInt16"] = SubtractSaturateUInt16,
["SubtractScalar.Double"] = SubtractScalarDouble,
+ ["SumAbsoluteDifferences.UInt16"] = SumAbsoluteDifferencesUInt16,
["UnpackHigh.Double"] = UnpackHighDouble,
["UnpackHigh.Int64"] = UnpackHighInt64,
["UnpackHigh.UInt64"] = UnpackHighUInt64,
<Compile Include="MinScalar.Double.cs" />
<Compile Include="Multiply.Double.cs" />
<Compile Include="MultiplyScalar.Double.cs" />
+ <Compile Include="MultiplyAddAdjacent.Int32.cs" />
<Compile Include="Or.Double.cs" />
<Compile Include="Or.Byte.cs" />
<Compile Include="Or.Int16.cs" />
<Compile Include="SubtractSaturate.Int16.cs"/>
<Compile Include="SubtractSaturate.UInt16.cs"/>
<Compile Include="SubtractScalar.Double.cs" />
+ <Compile Include="SumAbsoluteDifferences.UInt16.cs" />
<Compile Include="UnpackHigh.Double.cs" />
<Compile Include="UnpackHigh.Int64.cs" />
<Compile Include="UnpackHigh.UInt64.cs" />
<Compile Include="MinScalar.Double.cs" />
<Compile Include="Multiply.Double.cs" />
<Compile Include="MultiplyScalar.Double.cs" />
+ <Compile Include="MultiplyAddAdjacent.Int32.cs" />
<Compile Include="Or.Byte.cs" />
<Compile Include="Or.Double.cs" />
<Compile Include="Or.Int16.cs" />
<Compile Include="SubtractSaturate.SByte.cs"/>
<Compile Include="SubtractSaturate.UInt16.cs"/>
<Compile Include="SubtractScalar.Double.cs" />
+ <Compile Include="SumAbsoluteDifferences.UInt16.cs" />
<Compile Include="UnpackHigh.Double.cs" />
<Compile Include="UnpackHigh.Int64.cs" />
<Compile Include="UnpackHigh.UInt64.cs" />
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public static partial class Program
+ {
+ private static void SumAbsoluteDifferencesUInt16()
+ {
+ var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16();
+
+ if (test.IsSupported)
+ {
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates basic functionality works, using Load
+ test.RunBasicScenario_Load();
+
+ // Validates basic functionality works, using LoadAligned
+ test.RunBasicScenario_LoadAligned();
+ }
+
+ // Validates calling via reflection works, using Unsafe.Read
+ test.RunReflectionScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates calling via reflection works, using Load
+ test.RunReflectionScenario_Load();
+
+ // Validates calling via reflection works, using LoadAligned
+ test.RunReflectionScenario_LoadAligned();
+ }
+
+ // Validates passing a static member works
+ test.RunClsVarScenario();
+
+ // Validates passing a local works, using Unsafe.Read
+ test.RunLclVarScenario_UnsafeRead();
+
+ if (Sse2.IsSupported)
+ {
+ // Validates passing a local works, using Load
+ test.RunLclVarScenario_Load();
+
+ // Validates passing a local works, using LoadAligned
+ test.RunLclVarScenario_LoadAligned();
+ }
+
+ // Validates passing the field of a local class works
+ test.RunClassLclFldScenario();
+
+ // Validates passing an instance member of a class works
+ test.RunClassFldScenario();
+
+ // Validates passing the field of a local struct works
+ test.RunStructLclFldScenario();
+
+ // Validates passing an instance member of a struct works
+ test.RunStructFldScenario();
+ }
+ else
+ {
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }
+
+ if (!test.Succeeded)
+ {
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }
+ }
+ }
+
+ public sealed unsafe class SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16
+ {
+ private struct TestStruct
+ {
+ public Vector128<Byte> _fld1;
+ public Vector128<Byte> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref testStruct._fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref testStruct._fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16 testClass)
+ {
+ var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Byte>>() / sizeof(Byte);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Byte>>() / sizeof(Byte);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+
+ private static Byte[] _data1 = new Byte[Op1ElementCount];
+ private static Byte[] _data2 = new Byte[Op2ElementCount];
+
+ private static Vector128<Byte> _clsVar1;
+ private static Vector128<Byte> _clsVar2;
+
+ private Vector128<Byte> _fld1;
+ private Vector128<Byte> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<UInt16, Byte, Byte> _dataTable;
+
+ static SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _clsVar2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ }
+
+ public SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld1), ref Unsafe.As<Byte, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Byte>, byte>(ref _fld2), ref Unsafe.As<Byte, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetByte(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetByte(); }
+ _dataTable = new SimpleBinaryOpTest__DataTable<UInt16, Byte, Byte>(_data1, _data2, new UInt16[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse2.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse2.SumAbsoluteDifferences(
+ Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse2.SumAbsoluteDifferences(
+ Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse2.SumAbsoluteDifferences(
+ Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse2).GetMethod(nameof(Sse2.SumAbsoluteDifferences), new Type[] { typeof(Vector128<Byte>), typeof(Vector128<Byte>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse2.SumAbsoluteDifferences(
+ _clsVar1,
+ _clsVar2
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var left = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector128<Byte>>(_dataTable.inArray2Ptr);
+ var result = Sse2.SumAbsoluteDifferences(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var left = Sse2.LoadVector128((Byte*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadVector128((Byte*)(_dataTable.inArray2Ptr));
+ var result = Sse2.SumAbsoluteDifferences(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var left = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadAlignedVector128((Byte*)(_dataTable.inArray2Ptr));
+ var result = Sse2.SumAbsoluteDifferences(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__SumAbsoluteDifferencesUInt16();
+ var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse2.SumAbsoluteDifferences(_fld1, _fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse2.SumAbsoluteDifferences(test._fld1, test._fld2);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario));
+
+ var test = TestStruct.Create();
+ test.RunStructFldScenario(this);
+ }
+
+ public void RunUnsupportedScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario));
+
+ Succeeded = false;
+
+ try
+ {
+ RunBasicScenario_UnsafeRead();
+ }
+ catch (PlatformNotSupportedException)
+ {
+ Succeeded = true;
+ }
+ }
+
+ private void ValidateResult(Vector128<Byte> left, Vector128<Byte> right, void* result, [CallerMemberName] string method = "")
+ {
+ Byte[] inArray1 = new Byte[Op1ElementCount];
+ Byte[] inArray2 = new Byte[Op2ElementCount];
+ UInt16[] outArray = new UInt16[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ Byte[] inArray1 = new Byte[Op1ElementCount];
+ Byte[] inArray2 = new Byte[Op2ElementCount];
+ UInt16[] outArray = new UInt16[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Byte, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<Byte>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(Byte[] left, Byte[] right, UInt16[] result, [CallerMemberName] string method = "")
+ {
+ if (result[0] != Math.Abs(left[0] - right[0]) + Math.Abs(left[1] - right[1]) + Math.Abs(left[2] - right[2]) + Math.Abs(left[3] - right[3]) + Math.Abs(left[4] - right[4]) + Math.Abs(left[5] - right[5]) + Math.Abs(left[6] - right[6]) + Math.Abs(left[7] - right[7]))
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != (i != 4 ? 0 : Math.Abs(left[8] - right[8]) + Math.Abs(left[9] - right[9]) + Math.Abs(left[10] - right[10]) + Math.Abs(left[11] - right[11]) + Math.Abs(left[12] - right[12]) + Math.Abs(left[13] - right[13]) + Math.Abs(left[14] - right[14]) + Math.Abs(left[15] - right[15])))
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse2)}.{nameof(Sse2.SumAbsoluteDifferences)}<UInt16>(Vector128<Byte>, Vector128<Byte>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" left: ({string.Join(", ", left)})");
+ TestLibrary.TestFramework.LogInformation($" right: ({string.Join(", ", right)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}