--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{{
+ public static partial class Program
+ {{
+ private static void {2}{3}()
+ {{
+ var test = new SimpleTernaryOpTest__{2}{3}();
+
+ if (test.IsSupported)
+ {{
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ // 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();
+
+ // 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();
+
+ // 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 works
+ test.RunLclFldScenario();
+
+ // Validates passing an instance member works
+ test.RunFldScenario();
+ }}
+ else
+ {{
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }}
+
+ if (!test.Succeeded)
+ {{
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }}
+ }}
+ }}
+
+ public sealed unsafe class SimpleTernaryOpTest__{2}{3}
+ {{
+ private const int VectorSize = {5};
+ private const int ElementCount = VectorSize / sizeof({3});
+
+ private static {3}[] _data1 = new {3}[ElementCount];
+ private static {3}[] _data2 = new {3}[ElementCount];
+ private static {3}[] _data3 = new {3}[ElementCount];
+
+ private static {4}<{3}> _clsVar1;
+ private static {4}<{3}> _clsVar2;
+ private static {4}<{3}> _clsVar3;
+
+ private {4}<{3}> _fld1;
+ private {4}<{3}> _fld2;
+ private {4}<{3}> _fld3;
+
+ private SimpleTernaryOpTest__DataTable<{3}> _dataTable;
+
+ static SimpleTernaryOpTest__{2}{3}()
+ {{
+ var random = new Random();
+
+ for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; _data3[i] = {7}; }}
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar1), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar2), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar3), ref Unsafe.As<{3}, byte>(ref _data3[0]), VectorSize);
+ }}
+
+ public SimpleTernaryOpTest__{2}{3}()
+ {{
+ Succeeded = true;
+
+ var random = new Random();
+
+ for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; _data3[i] = {7}; }}
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld1), ref Unsafe.As<{3}, byte>(ref _data1[0]), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld2), ref Unsafe.As<{3}, byte>(ref _data2[0]), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld3), ref Unsafe.As<{3}, byte>(ref _data3[0]), VectorSize);
+
+ for (var i = 0; i < ElementCount; i++) {{ _data1[i] = {6}; _data2[i] = {6}; _data3[i] = {7}; }}
+ _dataTable = new SimpleTernaryOpTest__DataTable<{3}>(_data1, _data2, _data3, new {3}[ElementCount], VectorSize);
+ }}
+
+ public bool IsSupported => {0}.IsSupported;
+
+ public bool Succeeded {{ get; set; }}
+
+ public void RunBasicScenario_UnsafeRead()
+ {{
+ var result = {0}.{2}(
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray3Ptr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunBasicScenario_Load()
+ {{
+ var result = {0}.{2}(
+ {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)),
+ {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)),
+ {1}.Load{4}(({3}*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunBasicScenario_LoadAligned()
+ {{
+ var result = {0}.{2}(
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)),
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)),
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray3Ptr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_UnsafeRead()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>), typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr),
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr),
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArray3Ptr)
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_Load()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>), typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr)),
+ {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr)),
+ {1}.Load{4}(({3}*)(_dataTable.inArray3Ptr))
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_LoadAligned()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>), typeof({4}<{3}>), typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr)),
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr)),
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArray3Ptr))
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArray1Ptr, _dataTable.inArray2Ptr, _dataTable.inArray3Ptr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunClsVarScenario()
+ {{
+ var result = {0}.{2}(
+ _clsVar1,
+ _clsVar2,
+ _clsVar3
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar1, _clsVar2, _clsVar3, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_UnsafeRead()
+ {{
+ var firstOp = Unsafe.Read<{4}<{3}>>(_dataTable.inArray1Ptr);
+ var secondOp = Unsafe.Read<{4}<{3}>>(_dataTable.inArray2Ptr);
+ var thirdOp = Unsafe.Read<{4}<{3}>>(_dataTable.inArray3Ptr);
+ var result = {0}.{2}(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_Load()
+ {{
+ var firstOp = {1}.Load{4}(({3}*)(_dataTable.inArray1Ptr));
+ var secondOp = {1}.Load{4}(({3}*)(_dataTable.inArray2Ptr));
+ var thirdOp = {1}.Load{4}(({3}*)(_dataTable.inArray3Ptr));
+ var result = {0}.{2}(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_LoadAligned()
+ {{
+ var firstOp = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray1Ptr));
+ var secondOp = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray2Ptr));
+ var thirdOp = {1}.LoadAligned{4}(({3}*)(_dataTable.inArray3Ptr));
+ var result = {0}.{2}(firstOp, secondOp, thirdOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, secondOp, thirdOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclFldScenario()
+ {{
+ var test = new SimpleTernaryOpTest__{2}{3}();
+ var result = {0}.{2}(test._fld1, test._fld2, test._fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld1, test._fld2, test._fld3, _dataTable.outArrayPtr);
+ }}
+
+ public void RunFldScenario()
+ {{
+ var result = {0}.{2}(_fld1, _fld2, _fld3);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld1, _fld2, _fld3, _dataTable.outArrayPtr);
+ }}
+
+ public void RunUnsupportedScenario()
+ {{
+ Succeeded = false;
+
+ try
+ {{
+ RunBasicScenario_UnsafeRead();
+ }}
+ catch (PlatformNotSupportedException)
+ {{
+ Succeeded = true;
+ }}
+ }}
+
+ private void ValidateResult({4}<{3}> firstOp, {4}<{3}> secondOp, {4}<{3}> thirdOp, void* result, [CallerMemberName] string method = "")
+ {{
+ {3}[] inArray1 = new {3}[ElementCount];
+ {3}[] inArray2 = new {3}[ElementCount];
+ {3}[] inArray3 = new {3}[ElementCount];
+ {3}[] outArray = new {3}[ElementCount];
+
+ Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), firstOp);
+ Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), secondOp);
+ Unsafe.Write(Unsafe.AsPointer(ref inArray3[0]), thirdOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize);
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }}
+
+ private void ValidateResult(void* firstOp, void* secondOp, void* thirdOp, void* result, [CallerMemberName] string method = "")
+ {{
+ {3}[] inArray1 = new {3}[ElementCount];
+ {3}[] inArray2 = new {3}[ElementCount];
+ {3}[] inArray3 = new {3}[ElementCount];
+ {3}[] outArray = new {3}[ElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray1[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray2[0]), ref Unsafe.AsRef<byte>(secondOp), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray3[0]), ref Unsafe.AsRef<byte>(thirdOp), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize);
+
+ ValidateResult(inArray1, inArray2, inArray3, outArray, method);
+ }}
+
+ private void ValidateResult({3}[] firstOp, {3}[] secondOp, {3}[] thirdOp, {3}[] result, [CallerMemberName] string method = "")
+ {{
+ if ({8})
+ {{
+ Succeeded = false;
+ }}
+ else
+ {{
+ for (var i = 1; i < firstOp.Length; i++)
+ {{
+ if ({9})
+ {{
+ Succeeded = false;
+ break;
+ }}
+ }}
+ }}
+
+ if (!Succeeded)
+ {{
+ Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{3}>: {{method}} failed:");
+ Console.WriteLine($" firstOp: ({{string.Join(", ", firstOp)}})");
+ Console.WriteLine($" secondOp: ({{string.Join(", ", secondOp)}})");
+ Console.WriteLine($" thirdOp: ({{string.Join(", ", thirdOp)}})");
+ Console.WriteLine($" result: ({{string.Join(", ", result)}})");
+ Console.WriteLine();
+ }}
+ }}
+ }}
+}}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public unsafe struct SimpleTernaryOpTest__DataTable<T> : IDisposable where T : struct
+ {
+ private GCHandle inHandle1;
+ private GCHandle inHandle2;
+ private GCHandle inHandle3;
+ private GCHandle outHandle;
+
+ public T[] inArray1;
+ public T[] inArray2;
+ public T[] inArray3;
+ public T[] outArray;
+
+ public SimpleTernaryOpTest__DataTable(T[] inArray1, T[] inArray2, T[] inArray3, T[] outArray)
+ {
+ this.inArray1 = inArray1;
+ this.inArray2 = inArray2;
+ this.inArray3 = inArray3;
+ this.outArray = outArray;
+
+ this.inHandle1 = GCHandle.Alloc(inArray1, GCHandleType.Pinned);
+ this.inHandle2 = GCHandle.Alloc(inArray2, GCHandleType.Pinned);
+ this.inHandle3 = GCHandle.Alloc(inArray3, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned);
+ }
+
+ public void* inArray1Ptr => inHandle1.AddrOfPinnedObject().ToPointer();
+ public void* inArray2Ptr => inHandle2.AddrOfPinnedObject().ToPointer();
+ public void* inArray3Ptr => inHandle3.AddrOfPinnedObject().ToPointer();
+ public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer();
+
+ public void Dispose()
+ {
+ inHandle1.Free();
+ inHandle2.Free();
+ inHandle3.Free();
+ outHandle.Free();
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public unsafe struct SimpleTernaryOpTest__DataTable<T> : IDisposable where T : struct
+ {
+ private byte[] inArray1;
+ private byte[] inArray2;
+ private byte[] inArray3;
+ private byte[] outArray;
+
+ private GCHandle inHandle1;
+ private GCHandle inHandle2;
+ private GCHandle inHandle3;
+ private GCHandle outHandle;
+
+ private byte simdSize;
+
+ public SimpleTernaryOpTest__DataTable(T[] inArray1, T[] inArray2, T[] inArray3, T[] outArray, int simdSize)
+ {
+ this.inArray1 = new byte[simdSize * 2];
+ this.inArray2 = new byte[simdSize * 2];
+ this.inArray3 = new byte[simdSize * 2];
+ this.outArray = new byte[simdSize * 2];
+
+ this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned);
+ this.inHandle2 = GCHandle.Alloc(this.inArray2, GCHandleType.Pinned);
+ this.inHandle3 = GCHandle.Alloc(this.inArray3, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.simdSize = unchecked((byte)(simdSize));
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(inArray1Ptr), ref Unsafe.As<T, byte>(ref inArray1[0]), this.simdSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(inArray2Ptr), ref Unsafe.As<T, byte>(ref inArray2[0]), this.simdSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(inArray3Ptr), ref Unsafe.As<T, byte>(ref inArray3[0]), this.simdSize);
+ }
+
+ public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), simdSize);
+ public void* inArray2Ptr => Align((byte*)(inHandle2.AddrOfPinnedObject().ToPointer()), simdSize);
+ public void* inArray3Ptr => Align((byte*)(inHandle3.AddrOfPinnedObject().ToPointer()), simdSize);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), simdSize);
+
+ public void Dispose()
+ {
+ inHandle1.Free();
+ inHandle2.Free();
+ inHandle3.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, byte expectedAlignment)
+ {
+ // Compute how bad the misalignment is, which is at most (expectedAlignment - 1).
+ // Then subtract that from the expectedAlignment and add it to the original address
+ // to compute the aligned address.
+
+ var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment);
+ return (void*)(buffer + misalignment);
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+/******************************************************************************
+ * This file is auto-generated from a template file by the GenerateTests.csx *
+ * script in tests\src\JIT\HardwareIntrinsics\X86\Shared. In order to make *
+ * changes, please update the corresponding template and run according to the *
+ * directions listed in the file. *
+ ******************************************************************************/
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{{
+ public static partial class Program
+ {{
+ private static void {2}{3}()
+ {{
+ var test = new SimpleUnaryOpTest__{2}{3}();
+
+ if (test.IsSupported)
+ {{
+ // Validates basic functionality works, using Unsafe.Read
+ test.RunBasicScenario_UnsafeRead();
+
+ // 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();
+
+ // 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();
+
+ // 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 works
+ test.RunLclFldScenario();
+
+ // Validates passing an instance member works
+ test.RunFldScenario();
+ }}
+ else
+ {{
+ // Validates we throw on unsupported hardware
+ test.RunUnsupportedScenario();
+ }}
+
+ if (!test.Succeeded)
+ {{
+ throw new Exception("One or more scenarios did not complete as expected.");
+ }}
+ }}
+ }}
+
+ public sealed unsafe class SimpleUnaryOpTest__{2}{3}
+ {{
+ private const int VectorSize = {5};
+ private const int ElementCount = VectorSize / sizeof({3});
+
+ private static {3}[] _data = new {3}[ElementCount];
+
+ private static {4}<{3}> _clsVar;
+
+ private {4}<{3}> _fld;
+
+ private SimpleUnaryOpTest__DataTable<{3}> _dataTable;
+
+ static SimpleUnaryOpTest__{2}{3}()
+ {{
+ var random = new Random();
+
+ for (var i = 0; i < ElementCount; i++) {{ _data[i] = {6}; }}
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _clsVar), ref Unsafe.As<{3}, byte>(ref _data[0]), VectorSize);
+ }}
+
+ public SimpleUnaryOpTest__{2}{3}()
+ {{
+ Succeeded = true;
+
+ var random = new Random();
+
+ for (var i = 0; i < ElementCount; i++) {{ _data[i] = {6}; }}
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{4}<{3}>, byte>(ref _fld), ref Unsafe.As<{3}, byte>(ref _data[0]), VectorSize);
+
+ for (var i = 0; i < ElementCount; i++) {{ _data[i] = {6}; }}
+ _dataTable = new SimpleUnaryOpTest__DataTable<{3}>(_data, new {3}[ElementCount], VectorSize);
+ }}
+
+ public bool IsSupported => {0}.IsSupported;
+
+ public bool Succeeded {{ get; set; }}
+
+ public void RunBasicScenario_UnsafeRead()
+ {{
+ var result = {0}.{2}(
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArrayPtr)
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunBasicScenario_Load()
+ {{
+ var result = {0}.{2}(
+ {1}.Load{4}(({3}*)(_dataTable.inArrayPtr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunBasicScenario_LoadAligned()
+ {{
+ var result = {0}.{2}(
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArrayPtr))
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_UnsafeRead()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ Unsafe.Read<{4}<{3}>>(_dataTable.inArrayPtr)
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_Load()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ {1}.Load{4}(({3}*)(_dataTable.inArrayPtr))
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunReflectionScenario_LoadAligned()
+ {{
+ var result = typeof({0}).GetMethod(nameof({0}.{2}), new Type[] {{ typeof({4}<{3}>) }})
+ .Invoke(null, new object[] {{
+ {1}.LoadAligned{4}(({3}*)(_dataTable.inArrayPtr))
+ }});
+
+ Unsafe.Write(_dataTable.outArrayPtr, ({4}<{3}>)(result));
+ ValidateResult(_dataTable.inArrayPtr, _dataTable.outArrayPtr);
+ }}
+
+ public void RunClsVarScenario()
+ {{
+ var result = {0}.{2}(
+ _clsVar
+ );
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_clsVar, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_UnsafeRead()
+ {{
+ var firstOp = Unsafe.Read<{4}<{3}>>(_dataTable.inArrayPtr);
+ var result = {0}.{2}(firstOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_Load()
+ {{
+ var firstOp = {1}.Load{4}(({3}*)(_dataTable.inArrayPtr));
+ var result = {0}.{2}(firstOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclVarScenario_LoadAligned()
+ {{
+ var firstOp = {1}.LoadAligned{4}(({3}*)(_dataTable.inArrayPtr));
+ var result = {0}.{2}(firstOp);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(firstOp, _dataTable.outArrayPtr);
+ }}
+
+ public void RunLclFldScenario()
+ {{
+ var test = new SimpleUnaryOpTest__{2}{3}();
+ var result = {0}.{2}(test._fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(test._fld, _dataTable.outArrayPtr);
+ }}
+
+ public void RunFldScenario()
+ {{
+ var result = {0}.{2}(_fld);
+
+ Unsafe.Write(_dataTable.outArrayPtr, result);
+ ValidateResult(_fld, _dataTable.outArrayPtr);
+ }}
+
+ public void RunUnsupportedScenario()
+ {{
+ Succeeded = false;
+
+ try
+ {{
+ RunBasicScenario_UnsafeRead();
+ }}
+ catch (PlatformNotSupportedException)
+ {{
+ Succeeded = true;
+ }}
+ }}
+
+ private void ValidateResult({4}<{3}> firstOp, void* result, [CallerMemberName] string method = "")
+ {{
+ {3}[] inArray = new {3}[ElementCount];
+ {3}[] outArray = new {3}[ElementCount];
+
+ Unsafe.Write(Unsafe.AsPointer(ref inArray[0]), firstOp);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize);
+
+ ValidateResult(inArray, outArray, method);
+ }}
+
+ private void ValidateResult(void* firstOp, void* result, [CallerMemberName] string method = "")
+ {{
+ {3}[] inArray = new {3}[ElementCount];
+ {3}[] outArray = new {3}[ElementCount];
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref inArray[0]), ref Unsafe.AsRef<byte>(firstOp), VectorSize);
+ Unsafe.CopyBlockUnaligned(ref Unsafe.As<{3}, byte>(ref outArray[0]), ref Unsafe.AsRef<byte>(result), VectorSize);
+
+ ValidateResult(inArray, outArray, method);
+ }}
+
+ private void ValidateResult({3}[] firstOp, {3}[] result, [CallerMemberName] string method = "")
+ {{
+ if ({7})
+ {{
+ Succeeded = false;
+ }}
+ else
+ {{
+ for (var i = 1; i < firstOp.Length; i++)
+ {{
+ if ({8})
+ {{
+ Succeeded = false;
+ break;
+ }}
+ }}
+ }}
+
+ if (!Succeeded)
+ {{
+ Console.WriteLine($"{{nameof({0})}}.{{nameof({0}.{2})}}<{3}>: {{method}} failed:");
+ Console.WriteLine($" firstOp: ({{string.Join(", ", firstOp)}})");
+ Console.WriteLine($" result: ({{string.Join(", ", result)}})");
+ Console.WriteLine();
+ }}
+ }}
+ }}
+}}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public unsafe struct SimpleUnaryOpTest__DataTable<T> : IDisposable where T : struct
+ {
+ private GCHandle inHandle;
+ private GCHandle outHandle;
+
+ public T[] inArray;
+ public T[] outArray;
+
+ public SimpleUnaryOpTest__DataTable(T[] inArray, T[] outArray)
+ {
+ this.inArray = inArray;
+ this.outArray = outArray;
+
+ this.inHandle = GCHandle.Alloc(inArray, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(outArray, GCHandleType.Pinned);
+ }
+
+ public void* inArrayPtr => inHandle.AddrOfPinnedObject().ToPointer();
+ public void* outArrayPtr => outHandle.AddrOfPinnedObject().ToPointer();
+
+ public void Dispose()
+ {
+ inHandle.Free();
+ outHandle.Free();
+ }
+ }
+}
--- /dev/null
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System;
+using System.Runtime.CompilerServices;
+using System.Runtime.InteropServices;
+using System.Runtime.Intrinsics;
+using System.Runtime.Intrinsics.X86;
+
+namespace JIT.HardwareIntrinsics.X86
+{
+ public unsafe struct SimpleUnaryOpTest__DataTable<T> : IDisposable where T : struct
+ {
+ private byte[] inArray;
+ private byte[] outArray;
+
+ private GCHandle inHandle;
+ private GCHandle outHandle;
+
+ private byte simdSize;
+
+ public SimpleUnaryOpTest__DataTable(T[] inArray, T[] outArray, int simdSize)
+ {
+ this.inArray = new byte[simdSize * 2];
+ this.outArray = new byte[simdSize * 2];
+
+ this.inHandle = GCHandle.Alloc(this.inArray, GCHandleType.Pinned);
+ this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned);
+
+ this.simdSize = unchecked((byte)(simdSize));
+
+ Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef<byte>(inArrayPtr), ref Unsafe.As<T, byte>(ref inArray[0]), this.simdSize);
+ }
+
+ public void* inArrayPtr => Align((byte*)(inHandle.AddrOfPinnedObject().ToPointer()), simdSize);
+ public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), simdSize);
+
+ public void Dispose()
+ {
+ inHandle.Free();
+ outHandle.Free();
+ }
+
+ private static unsafe void* Align(byte* buffer, byte expectedAlignment)
+ {
+ // Compute how bad the misalignment is, which is at most (expectedAlignment - 1).
+ // Then subtract that from the expectedAlignment and add it to the original address
+ // to compute the aligned address.
+
+ var misalignment = expectedAlignment - ((ulong)(buffer) % expectedAlignment);
+ return (void*)(buffer + misalignment);
+ }
+ }
+}