summaryrefslogtreecommitdiff
path: root/tests/src/JIT/HardwareIntrinsics/X86/Sse41
diff options
context:
space:
mode:
authorCarol Eidt <carol.eidt@microsoft.com>2018-10-08 16:38:31 +0000
committerGitHub <noreply@github.com>2018-10-08 16:38:31 +0000
commit426b9f89e45993db52e4d1b87111907ad5b78b4a (patch)
tree6ab83cd15354f2bb9044cd4f7f399913abd89b55 /tests/src/JIT/HardwareIntrinsics/X86/Sse41
parentdbf0bf11d120b2f7837ba767a7836b44474c82a5 (diff)
parent54af6bd370c1a93f6bc4041f06822a247f4b6f9a (diff)
downloadcoreclr-426b9f89e45993db52e4d1b87111907ad5b78b4a.tar.gz
coreclr-426b9f89e45993db52e4d1b87111907ad5b78b4a.tar.bz2
coreclr-426b9f89e45993db52e4d1b87111907ad5b78b4a.zip
Merge pull request #20210 from fiigii/lastavx2
Implement the remaining AVX2 intrinsic
Diffstat (limited to 'tests/src/JIT/HardwareIntrinsics/X86/Sse41')
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int16.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int32.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int64.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt16.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt32.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt64.cs430
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.UInt32.cs403
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs7
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj7
-rw-r--r--tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj7
10 files changed, 3004 insertions, 0 deletions
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int16.cs
new file mode 100644
index 0000000000..51d3a38757
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int16.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableInt16()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableInt16();
+
+ 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 SimpleTernaryOpTest__BlendVariableInt16
+ {
+ private struct TestStruct
+ {
+ public Vector128<Int16> _fld1;
+ public Vector128<Int16> _fld2;
+ public Vector128<Int16> _fld3;
+
+ 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>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt16("0xFFFF", 16) : (short)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar3), ref Unsafe.As<Int16, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableInt16 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, 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 Op3ElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Int16>>() / sizeof(Int16);
+
+ private static Int16[] _data1 = new Int16[Op1ElementCount];
+ private static Int16[] _data2 = new Int16[Op2ElementCount];
+ private static Int16[] _data3 = new Int16[Op3ElementCount];
+
+ private static Vector128<Int16> _clsVar1;
+ private static Vector128<Int16> _clsVar2;
+ private static Vector128<Int16> _clsVar3;
+
+ private Vector128<Int16> _fld1;
+ private Vector128<Int16> _fld2;
+ private Vector128<Int16> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<Int16, Int16, Int16, Int16> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableInt16()
+ {
+ 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>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt16("0xFFFF", 16) : (short)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _clsVar3), ref Unsafe.As<Int16, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableInt16()
+ {
+ 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 < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt16("0xFFFF", 16) : (short)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int16>, byte>(ref _fld3), ref Unsafe.As<Int16, byte>(ref _data3[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(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt16("0xFFFF", 16) : (short)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<Int16, Int16, Int16, Int16>(_data1, _data2, _data3, new Int16[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int16>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int16*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int16>), typeof(Vector128<Int16>), typeof(Vector128<Int16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<Int16>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((Int16*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((Int16*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((Int16*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((Int16*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableInt16();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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> firstOp, Vector128<Int16> secondOp, Vector128<Int16> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int16[] inArray1 = new Int16[Op1ElementCount];
+ Int16[] inArray2 = new Int16[Op2ElementCount];
+ Int16[] inArray3 = new Int16[Op3ElementCount];
+ Int16[] outArray = new Int16[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int16, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int16[] inArray1 = new Int16[Op1ElementCount];
+ Int16[] inArray2 = new Int16[Op2ElementCount];
+ Int16[] inArray3 = new Int16[Op3ElementCount];
+ Int16[] outArray = new Int16[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int16>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(Int16[] firstOp, Int16[] secondOp, Int16[] thirdOp, Int16[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<Int16>(Vector128<Int16>, Vector128<Int16>, Vector128<Int16>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int32.cs
new file mode 100644
index 0000000000..1fcb6fc988
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int32.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableInt32()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableInt32();
+
+ 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 SimpleTernaryOpTest__BlendVariableInt32
+ {
+ private struct TestStruct
+ {
+ public Vector128<Int32> _fld1;
+ public Vector128<Int32> _fld2;
+ public Vector128<Int32> _fld3;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref testStruct._fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref testStruct._fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt32("0xFFFFFFFF", 16) : (int)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar3), ref Unsafe.As<Int32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableInt32 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+ private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Int32>>() / sizeof(Int32);
+
+ private static Int32[] _data1 = new Int32[Op1ElementCount];
+ private static Int32[] _data2 = new Int32[Op2ElementCount];
+ private static Int32[] _data3 = new Int32[Op3ElementCount];
+
+ private static Vector128<Int32> _clsVar1;
+ private static Vector128<Int32> _clsVar2;
+ private static Vector128<Int32> _clsVar3;
+
+ private Vector128<Int32> _fld1;
+ private Vector128<Int32> _fld2;
+ private Vector128<Int32> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<Int32, Int32, Int32, Int32> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableInt32()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt32("0xFFFFFFFF", 16) : (int)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _clsVar3), ref Unsafe.As<Int32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableInt32()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld1), ref Unsafe.As<Int32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld2), ref Unsafe.As<Int32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt32("0xFFFFFFFF", 16) : (int)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int32>, byte>(ref _fld3), ref Unsafe.As<Int32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt32(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt32(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt32("0xFFFFFFFF", 16) : (int)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<Int32, Int32, Int32, Int32>(_data1, _data2, _data3, new Int32[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int32>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int32*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int32>), typeof(Vector128<Int32>), typeof(Vector128<Int32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<Int32>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((Int32*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((Int32*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((Int32*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((Int32*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableInt32();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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<Int32> firstOp, Vector128<Int32> secondOp, Vector128<Int32> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int32[] inArray1 = new Int32[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Int32[] inArray3 = new Int32[Op3ElementCount];
+ Int32[] outArray = new Int32[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int32, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int32[] inArray1 = new Int32[Op1ElementCount];
+ Int32[] inArray2 = new Int32[Op2ElementCount];
+ Int32[] inArray3 = new Int32[Op3ElementCount];
+ Int32[] outArray = new Int32[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int32>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(Int32[] firstOp, Int32[] secondOp, Int32[] thirdOp, Int32[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<Int32>(Vector128<Int32>, Vector128<Int32>, Vector128<Int32>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int64.cs
new file mode 100644
index 0000000000..3f72e11a05
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.Int64.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableInt64()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableInt64();
+
+ 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 SimpleTernaryOpTest__BlendVariableInt64
+ {
+ private struct TestStruct
+ {
+ public Vector128<Int64> _fld1;
+ public Vector128<Int64> _fld2;
+ public Vector128<Int64> _fld3;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref testStruct._fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref testStruct._fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt64("0xFFFFFFFFFFFFFFFF", 16) : (long)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar3), ref Unsafe.As<Int64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableInt64 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<Int64>>() / sizeof(Int64);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<Int64>>() / sizeof(Int64);
+ private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector128<Int64>>() / sizeof(Int64);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<Int64>>() / sizeof(Int64);
+
+ private static Int64[] _data1 = new Int64[Op1ElementCount];
+ private static Int64[] _data2 = new Int64[Op2ElementCount];
+ private static Int64[] _data3 = new Int64[Op3ElementCount];
+
+ private static Vector128<Int64> _clsVar1;
+ private static Vector128<Int64> _clsVar2;
+ private static Vector128<Int64> _clsVar3;
+
+ private Vector128<Int64> _fld1;
+ private Vector128<Int64> _fld2;
+ private Vector128<Int64> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<Int64, Int64, Int64, Int64> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableInt64()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar1), ref Unsafe.As<Int64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt64("0xFFFFFFFFFFFFFFFF", 16) : (long)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _clsVar3), ref Unsafe.As<Int64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableInt64()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld1), ref Unsafe.As<Int64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld2), ref Unsafe.As<Int64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt64("0xFFFFFFFFFFFFFFFF", 16) : (long)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<Int64>, byte>(ref _fld3), ref Unsafe.As<Int64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetInt64(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetInt64(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToInt64("0xFFFFFFFFFFFFFFFF", 16) : (long)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<Int64, Int64, Int64, Int64>(_data1, _data2, _data3, new Int64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<Int64>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((Int64*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<Int64>), typeof(Vector128<Int64>), typeof(Vector128<Int64>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<Int64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<Int64>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((Int64*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((Int64*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((Int64*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((Int64*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableInt64();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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<Int64> firstOp, Vector128<Int64> secondOp, Vector128<Int64> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] inArray1 = new Int64[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Int64[] inArray3 = new Int64[Op3ElementCount];
+ Int64[] outArray = new Int64[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<Int64, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ Int64[] inArray1 = new Int64[Op1ElementCount];
+ Int64[] inArray2 = new Int64[Op2ElementCount];
+ Int64[] inArray3 = new Int64[Op3ElementCount];
+ Int64[] outArray = new Int64[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Int64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<Int64>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(Int64[] firstOp, Int64[] secondOp, Int64[] thirdOp, Int64[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<Int64>(Vector128<Int64>, Vector128<Int64>, Vector128<Int64>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt16.cs
new file mode 100644
index 0000000000..fb85c99260
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt16.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableUInt16()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableUInt16();
+
+ 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 SimpleTernaryOpTest__BlendVariableUInt16
+ {
+ private struct TestStruct
+ {
+ public Vector128<UInt16> _fld1;
+ public Vector128<UInt16> _fld2;
+ public Vector128<UInt16> _fld3;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref testStruct._fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref testStruct._fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt16("0xFFFF", 16) : (ushort)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar3), ref Unsafe.As<UInt16, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableUInt16 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+ private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt16>>() / sizeof(UInt16);
+
+ private static UInt16[] _data1 = new UInt16[Op1ElementCount];
+ private static UInt16[] _data2 = new UInt16[Op2ElementCount];
+ private static UInt16[] _data3 = new UInt16[Op3ElementCount];
+
+ private static Vector128<UInt16> _clsVar1;
+ private static Vector128<UInt16> _clsVar2;
+ private static Vector128<UInt16> _clsVar3;
+
+ private Vector128<UInt16> _fld1;
+ private Vector128<UInt16> _fld2;
+ private Vector128<UInt16> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<UInt16, UInt16, UInt16, UInt16> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableUInt16()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt16("0xFFFF", 16) : (ushort)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _clsVar3), ref Unsafe.As<UInt16, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableUInt16()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld1), ref Unsafe.As<UInt16, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld2), ref Unsafe.As<UInt16, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt16("0xFFFF", 16) : (ushort)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt16>, byte>(ref _fld3), ref Unsafe.As<UInt16, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt16(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt16(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt16("0xFFFF", 16) : (ushort)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<UInt16, UInt16, UInt16, UInt16>(_data1, _data2, _data3, new UInt16[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt16*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt16>), typeof(Vector128<UInt16>), typeof(Vector128<UInt16>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt16>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<UInt16>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((UInt16*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((UInt16*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableUInt16();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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<UInt16> firstOp, Vector128<UInt16> secondOp, Vector128<UInt16> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt16[] inArray1 = new UInt16[Op1ElementCount];
+ UInt16[] inArray2 = new UInt16[Op2ElementCount];
+ UInt16[] inArray3 = new UInt16[Op3ElementCount];
+ UInt16[] outArray = new UInt16[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt16[] inArray1 = new UInt16[Op1ElementCount];
+ UInt16[] inArray2 = new UInt16[Op2ElementCount];
+ UInt16[] inArray3 = new UInt16[Op3ElementCount];
+ UInt16[] outArray = new UInt16[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt16, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt16>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(UInt16[] firstOp, UInt16[] secondOp, UInt16[] thirdOp, UInt16[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<UInt16>(Vector128<UInt16>, Vector128<UInt16>, Vector128<UInt16>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt32.cs
new file mode 100644
index 0000000000..7e0e95fdcf
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt32.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableUInt32()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableUInt32();
+
+ 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 SimpleTernaryOpTest__BlendVariableUInt32
+ {
+ private struct TestStruct
+ {
+ public Vector128<UInt32> _fld1;
+ public Vector128<UInt32> _fld2;
+ public Vector128<UInt32> _fld3;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref testStruct._fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref testStruct._fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt32("0xFFFFFFFF", 16) : (uint)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar3), ref Unsafe.As<UInt32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableUInt32 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+ private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+
+ private static UInt32[] _data1 = new UInt32[Op1ElementCount];
+ private static UInt32[] _data2 = new UInt32[Op2ElementCount];
+ private static UInt32[] _data3 = new UInt32[Op3ElementCount];
+
+ private static Vector128<UInt32> _clsVar1;
+ private static Vector128<UInt32> _clsVar2;
+ private static Vector128<UInt32> _clsVar3;
+
+ private Vector128<UInt32> _fld1;
+ private Vector128<UInt32> _fld2;
+ private Vector128<UInt32> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<UInt32, UInt32, UInt32, UInt32> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableUInt32()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt32("0xFFFFFFFF", 16) : (uint)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar3), ref Unsafe.As<UInt32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableUInt32()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt32("0xFFFFFFFF", 16) : (uint)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld3), ref Unsafe.As<UInt32, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt32("0xFFFFFFFF", 16) : (uint)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<UInt32, UInt32, UInt32, UInt32>(_data1, _data2, _data3, new UInt32[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((UInt32*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableUInt32();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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<UInt32> firstOp, Vector128<UInt32> secondOp, Vector128<UInt32> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt32[] inArray1 = new UInt32[Op1ElementCount];
+ UInt32[] inArray2 = new UInt32[Op2ElementCount];
+ UInt32[] inArray3 = new UInt32[Op3ElementCount];
+ UInt32[] outArray = new UInt32[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt32[] inArray1 = new UInt32[Op1ElementCount];
+ UInt32[] inArray2 = new UInt32[Op2ElementCount];
+ UInt32[] inArray3 = new UInt32[Op3ElementCount];
+ UInt32[] outArray = new UInt32[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(UInt32[] firstOp, UInt32[] secondOp, UInt32[] thirdOp, UInt32[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<UInt32>(Vector128<UInt32>, Vector128<UInt32>, Vector128<UInt32>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt64.cs
new file mode 100644
index 0000000000..d75d21c270
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/BlendVariable.UInt64.cs
@@ -0,0 +1,430 @@
+// 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 BlendVariableUInt64()
+ {
+ var test = new SimpleTernaryOpTest__BlendVariableUInt64();
+
+ 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 SimpleTernaryOpTest__BlendVariableUInt64
+ {
+ private struct TestStruct
+ {
+ public Vector128<UInt64> _fld1;
+ public Vector128<UInt64> _fld2;
+ public Vector128<UInt64> _fld3;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref testStruct._fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref testStruct._fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt64("0xFFFFFFFFFFFFFFFF", 16): (ulong)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar3), ref Unsafe.As<UInt64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleTernaryOpTest__BlendVariableUInt64 testClass)
+ {
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(testClass._dataTable.outArrayPtr, result);
+ testClass.ValidateResult(_fld1, _fld2, _fld3, testClass._dataTable.outArrayPtr);
+ }
+ }
+
+ private static readonly int LargestVectorSize = 16;
+
+ private static readonly int Op1ElementCount = Unsafe.SizeOf<Vector128<UInt64>>() / sizeof(UInt64);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<UInt64>>() / sizeof(UInt64);
+ private static readonly int Op3ElementCount = Unsafe.SizeOf<Vector128<UInt64>>() / sizeof(UInt64);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt64>>() / sizeof(UInt64);
+
+ private static UInt64[] _data1 = new UInt64[Op1ElementCount];
+ private static UInt64[] _data2 = new UInt64[Op2ElementCount];
+ private static UInt64[] _data3 = new UInt64[Op3ElementCount];
+
+ private static Vector128<UInt64> _clsVar1;
+ private static Vector128<UInt64> _clsVar2;
+ private static Vector128<UInt64> _clsVar3;
+
+ private Vector128<UInt64> _fld1;
+ private Vector128<UInt64> _fld2;
+ private Vector128<UInt64> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<UInt64, UInt64, UInt64, UInt64> _dataTable;
+
+ static SimpleTernaryOpTest__BlendVariableUInt64()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt64("0xFFFFFFFFFFFFFFFF", 16): (ulong)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _clsVar3), ref Unsafe.As<UInt64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ }
+
+ public SimpleTernaryOpTest__BlendVariableUInt64()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld1), ref Unsafe.As<UInt64, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld2), ref Unsafe.As<UInt64, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt64("0xFFFFFFFFFFFFFFFF", 16): (ulong)0); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt64>, byte>(ref _fld3), ref Unsafe.As<UInt64, byte>(ref _data3[0]), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt64(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt64(); }
+ for (var i = 0; i < Op3ElementCount; i++) { _data3[i] = (((i % 2) == 0) ? Convert.ToUInt64("0xFFFFFFFFFFFFFFFF", 16): (ulong)0); }
+ _dataTable = new SimpleTernaryOpTest__DataTable<UInt64, UInt64, UInt64, UInt64>(_data1, _data2, _data3, new UInt64[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.BlendVariable(
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunBasicScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned));
+
+ var result = Sse41.BlendVariable(
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray3Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadVector128((UInt64*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.BlendVariable), new Type[] { typeof(Vector128<UInt64>), typeof(Vector128<UInt64>), typeof(Vector128<UInt64>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr)),
+ Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray3Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt64>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.BlendVariable(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead));
+
+ var firstOp = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<Vector128<UInt64>>(_dataTable.inArray3Ptr);
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load));
+
+ var firstOp = Sse2.LoadVector128((UInt64*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadVector128((UInt64*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadVector128((UInt64*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunLclVarScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned));
+
+ var firstOp = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray1Ptr));
+ var secondOp = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray2Ptr));
+ var thirdOp = Sse2.LoadAlignedVector128((UInt64*)(_dataTable.inArray3Ptr));
+ var result = Sse41.BlendVariable(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleTernaryOpTest__BlendVariableUInt64();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario));
+
+ var result = Sse41.BlendVariable(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }
+
+ public void RunStructLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario));
+
+ var test = TestStruct.Create();
+ var result = Sse41.BlendVariable(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _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<UInt64> firstOp, Vector128<UInt64> secondOp, Vector128<UInt64> thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] inArray1 = new UInt64[Op1ElementCount];
+ UInt64[] inArray2 = new UInt64[Op2ElementCount];
+ UInt64[] inArray3 = new UInt64[Op3ElementCount];
+ UInt64[] outArray = new UInt64[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), firstOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), secondOp);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {
+ UInt64[] inArray1 = new UInt64[Op1ElementCount];
+ UInt64[] inArray2 = new UInt64[Op2ElementCount];
+ UInt64[] inArray3 = new UInt64[Op3ElementCount];
+ UInt64[] outArray = new UInt64[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt64, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt64>>());
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }
+
+ private void ValidateResult(UInt64[] firstOp, UInt64[] secondOp, UInt64[] thirdOp, UInt64[] result, [CallerMemberName] string method = "")
+ {
+ if ((thirdOp[0] != 0) ? secondOp[0] != result[0] : firstOp[0] != result[0])
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if ((thirdOp[i] != 0) ? secondOp[i] != result[i] : firstOp[i] != result[i])
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.BlendVariable)}<UInt64>(Vector128<UInt64>, Vector128<UInt64>, Vector128<UInt64>): {method} failed:");
+ TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})");
+ TestLibrary.TestFramework.LogInformation($" secondOp: ({string.Join(", ", secondOp)})");
+ TestLibrary.TestFramework.LogInformation($" thirdOp: ({string.Join(", ", thirdOp)})");
+ TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})");
+ TestLibrary.TestFramework.LogInformation(string.Empty);
+ }
+ }
+ }
+}
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.UInt32.cs
new file mode 100644
index 0000000000..09ecb527c0
--- /dev/null
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/MultiplyLow.UInt32.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 MultiplyLowUInt32()
+ {
+ var test = new SimpleBinaryOpTest__MultiplyLowUInt32();
+
+ 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__MultiplyLowUInt32
+ {
+ private struct TestStruct
+ {
+ public Vector128<UInt32> _fld1;
+ public Vector128<UInt32> _fld2;
+
+ public static TestStruct Create()
+ {
+ var testStruct = new TestStruct();
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref testStruct._fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref testStruct._fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ return testStruct;
+ }
+
+ public void RunStructFldScenario(SimpleBinaryOpTest__MultiplyLowUInt32 testClass)
+ {
+ var result = Sse41.MultiplyLow(_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<UInt32>>() / sizeof(UInt32);
+ private static readonly int Op2ElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+ private static readonly int RetElementCount = Unsafe.SizeOf<Vector128<UInt32>>() / sizeof(UInt32);
+
+ private static UInt32[] _data1 = new UInt32[Op1ElementCount];
+ private static UInt32[] _data2 = new UInt32[Op2ElementCount];
+
+ private static Vector128<UInt32> _clsVar1;
+ private static Vector128<UInt32> _clsVar2;
+
+ private Vector128<UInt32> _fld1;
+ private Vector128<UInt32> _fld2;
+
+ private SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32> _dataTable;
+
+ static SimpleBinaryOpTest__MultiplyLowUInt32()
+ {
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _clsVar2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ }
+
+ public SimpleBinaryOpTest__MultiplyLowUInt32()
+ {
+ Succeeded = true;
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld1), ref Unsafe.As<UInt32, byte>(ref _data1[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<Vector128<UInt32>, byte>(ref _fld2), ref Unsafe.As<UInt32, byte>(ref _data2[0]), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetUInt32(); }
+ for (var i = 0; i < Op2ElementCount; i++) { _data2[i] = TestLibrary.Generator.GetUInt32(); }
+ _dataTable = new SimpleBinaryOpTest__DataTable<UInt32, UInt32, UInt32>(_data1, _data2, new UInt32[RetElementCount], LargestVectorSize);
+ }
+
+ public bool IsSupported => Sse41.IsSupported;
+
+ public bool Succeeded { get; set; }
+
+ public void RunBasicScenario_UnsafeRead()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead));
+
+ var result = Sse41.MultiplyLow(
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_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 = Sse41.MultiplyLow(
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt32*)(_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 = Sse41.MultiplyLow(
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_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(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr)
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_Load()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunReflectionScenario_LoadAligned()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned));
+
+ var result = typeof(Sse41).GetMethod(nameof(Sse41.MultiplyLow), new Type[] { typeof(Vector128<UInt32>), typeof(Vector128<UInt32>) })
+ .Invoke(null, new object[] {
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray1Ptr)),
+ Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr))
+ });
+
+ Unsafe.Write(_dataTable.outArrayPtr, (Vector128<UInt32>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.outArrayPtr);
+ }
+
+ public void RunClsVarScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario));
+
+ var result = Sse41.MultiplyLow(
+ _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<UInt32>>(_dataTable.inArray1Ptr);
+ var right = Unsafe.Read<Vector128<UInt32>>(_dataTable.inArray2Ptr);
+ var result = Sse41.MultiplyLow(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((UInt32*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadVector128((UInt32*)(_dataTable.inArray2Ptr));
+ var result = Sse41.MultiplyLow(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((UInt32*)(_dataTable.inArray1Ptr));
+ var right = Sse2.LoadAlignedVector128((UInt32*)(_dataTable.inArray2Ptr));
+ var result = Sse41.MultiplyLow(left, right);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(left, right, _dataTable.outArrayPtr);
+ }
+
+ public void RunClassLclFldScenario()
+ {
+ TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario));
+
+ var test = new SimpleBinaryOpTest__MultiplyLowUInt32();
+ var result = Sse41.MultiplyLow(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 = Sse41.MultiplyLow(_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 = Sse41.MultiplyLow(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<UInt32> left, Vector128<UInt32> right, void* result, [CallerMemberName] string method = "")
+ {
+ UInt32[] inArray1 = new UInt32[Op1ElementCount];
+ UInt32[] inArray2 = new UInt32[Op2ElementCount];
+ UInt32[] outArray = new UInt32[RetElementCount];
+
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), left);
+ Unsafe.WriteUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), right);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(void* left, void* right, void* result, [CallerMemberName] string method = "")
+ {
+ UInt32[] inArray1 = new UInt32[Op1ElementCount];
+ UInt32[] inArray2 = new UInt32[Op2ElementCount];
+ UInt32[] outArray = new UInt32[RetElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(left), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(right), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<UInt32, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), (uint)Unsafe.SizeOf<Vector128<UInt32>>());
+
+ ValidateResult(inArray1, inArray2, outArray, method);
+ }
+
+ private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "")
+ {
+ if (result[0] != BitConverter.ToUInt32(BitConverter.GetBytes(((ulong)(left[0])) * right[0]), 0))
+ {
+ Succeeded = false;
+ }
+ else
+ {
+ for (var i = 1; i < RetElementCount; i++)
+ {
+ if (result[i] != BitConverter.ToUInt32(BitConverter.GetBytes(((ulong)(left[i])) * right[i]), 0))
+ {
+ Succeeded = false;
+ break;
+ }
+ }
+ }
+
+ if (!Succeeded)
+ {
+ TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.MultiplyLow)}<UInt32>(Vector128<UInt32>, Vector128<UInt32>): {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/Sse41/Program.Sse41.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs
index 542e9364bf..7286e23783 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Program.Sse41.cs
@@ -16,6 +16,12 @@ namespace JIT.HardwareIntrinsics.X86
["BlendVariable.Double"] = BlendVariableDouble,
["BlendVariable.SByte"] = BlendVariableSByte,
["BlendVariable.Single"] = BlendVariableSingle,
+ ["BlendVariable.Int16"] = BlendVariableInt16,
+ ["BlendVariable.UInt16"] = BlendVariableUInt16,
+ ["BlendVariable.Int32"] = BlendVariableInt32,
+ ["BlendVariable.UInt32"] = BlendVariableUInt32,
+ ["BlendVariable.Int64"] = BlendVariableInt64,
+ ["BlendVariable.UInt64"] = BlendVariableUInt64,
["Ceiling.Double"] = CeilingDouble,
["Ceiling.Single"] = CeilingSingle,
["CeilingScalar.Double"] = CeilingScalarDouble,
@@ -71,6 +77,7 @@ namespace JIT.HardwareIntrinsics.X86
["Min.UInt16"] = MinUInt16,
["Min.UInt32"] = MinUInt32,
["MultiplyLow.Int32"] = MultiplyLowInt32,
+ ["MultiplyLow.UInt32"] = MultiplyLowUInt32,
["PackUnsignedSaturate.UInt16"] = PackUnsignedSaturateUInt16,
["RoundCurrentDirection.Double"] = RoundCurrentDirectionDouble,
["RoundCurrentDirection.Single"] = RoundCurrentDirectionSingle,
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj
index 50f4c3ca22..4677ddd6bd 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_r.csproj
@@ -31,6 +31,12 @@
<Compile Include="BlendVariable.Double.cs" />
<Compile Include="BlendVariable.SByte.cs" />
<Compile Include="BlendVariable.Single.cs" />
+ <Compile Include="BlendVariable.Int16.cs" />
+ <Compile Include="BlendVariable.UInt16.cs" />
+ <Compile Include="BlendVariable.Int32.cs" />
+ <Compile Include="BlendVariable.UInt32.cs" />
+ <Compile Include="BlendVariable.Int64.cs" />
+ <Compile Include="BlendVariable.UInt64.cs" />
<Compile Include="Ceiling.Double.cs" />
<Compile Include="Ceiling.Single.cs" />
<Compile Include="CeilingScalar.Double.cs" />
@@ -50,6 +56,7 @@
<Compile Include="Min.UInt16.cs" />
<Compile Include="Min.UInt32.cs" />
<Compile Include="MultiplyLow.Int32.cs" />
+ <Compile Include="MultiplyLow.UInt32.cs" />
<Compile Include="PackUnsignedSaturate.UInt16.cs" />
<Compile Include="RoundCurrentDirection.Double.cs" />
<Compile Include="RoundCurrentDirection.Single.cs" />
diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj
index 2fb94fb58f..19ded7d0b4 100644
--- a/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj
+++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41/Sse41_ro.csproj
@@ -31,6 +31,12 @@
<Compile Include="BlendVariable.Double.cs" />
<Compile Include="BlendVariable.SByte.cs" />
<Compile Include="BlendVariable.Single.cs" />
+ <Compile Include="BlendVariable.Int16.cs" />
+ <Compile Include="BlendVariable.UInt16.cs" />
+ <Compile Include="BlendVariable.Int32.cs" />
+ <Compile Include="BlendVariable.UInt32.cs" />
+ <Compile Include="BlendVariable.Int64.cs" />
+ <Compile Include="BlendVariable.UInt64.cs" />
<Compile Include="Ceiling.Double.cs" />
<Compile Include="Ceiling.Single.cs" />
<Compile Include="CeilingScalar.Double.cs" />
@@ -50,6 +56,7 @@
<Compile Include="Min.UInt16.cs" />
<Compile Include="Min.UInt32.cs" />
<Compile Include="MultiplyLow.Int32.cs" />
+ <Compile Include="MultiplyLow.UInt32.cs" />
<Compile Include="PackUnsignedSaturate.UInt16.cs" />
<Compile Include="RoundCurrentDirection.Double.cs" />
<Compile Include="RoundCurrentDirection.Single.cs" />