From ba7172f5f4ae71f492b9bb129d98d932f987e0c5 Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Sat, 27 Jan 2018 15:30:36 -0800 Subject: [PATCH] Updating the Avx2.Add HardwareIntrinsic tests to be generated from a template. --- .../JIT/HardwareIntrinsics/X86/Avx2/Add.Byte.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.Int16.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.Int32.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.Int64.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.SByte.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.UInt16.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.UInt32.cs | 209 +++++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Avx2/Add.UInt64.cs | 209 +++++++++++++++++++++ .../X86/Avx2/{Add_r.csproj => Avx2_r.csproj} | 12 +- .../X86/Avx2/{Add_ro.csproj => Avx2_ro.csproj} | 12 +- .../HardwareIntrinsics/X86/Avx2/Program.Avx2.cs | 26 +++ .../X86/Shared/GenerateTests.csx | 14 ++ 12 files changed, 1734 insertions(+), 2 deletions(-) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Byte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.SByte.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt16.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt64.cs rename tests/src/JIT/HardwareIntrinsics/X86/Avx2/{Add_r.csproj => Avx2_r.csproj} (79%) rename tests/src/JIT/HardwareIntrinsics/X86/Avx2/{Add_ro.csproj => Avx2_ro.csproj} (79%) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Byte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Byte.cs new file mode 100644 index 0000000..4844728 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Byte.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddByte() + { + var test = new SimpleBinaryOpTest__AddByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddByte + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(Byte); + + private static Byte[] _data1 = new Byte[ElementCount]; + private static Byte[] _data2 = new Byte[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (byte)(random.Next(0, byte.MaxValue)); _data2[i] = (byte)(random.Next(0, byte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Byte[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddByte(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, Byte[] result, [CallerMemberName] string method = "") + { + Byte[] inArray1 = new Byte[ElementCount]; + Byte[] inArray2 = new Byte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Byte[] left, Byte[] right, Byte[] result, [CallerMemberName] string method = "") + { + if ((byte)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((byte)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int16.cs new file mode 100644 index 0000000..7123852 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int16.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddInt16() + { + var test = new SimpleBinaryOpTest__AddInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddInt16 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(Int16); + + private static Int16[] _data1 = new Int16[ElementCount]; + private static Int16[] _data2 = new Int16[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (short)(random.Next(short.MinValue, short.MaxValue)); _data2[i] = (short)(random.Next(short.MinValue, short.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Int16[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddInt16(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, Int16[] result, [CallerMemberName] string method = "") + { + Int16[] inArray1 = new Int16[ElementCount]; + Int16[] inArray2 = new Int16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int16[] left, Int16[] right, Int16[] result, [CallerMemberName] string method = "") + { + if ((short)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((short)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int32.cs new file mode 100644 index 0000000..2b1248e --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int32.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddInt32() + { + var test = new SimpleBinaryOpTest__AddInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddInt32 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(Int32); + + private static Int32[] _data1 = new Int32[ElementCount]; + private static Int32[] _data2 = new Int32[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (int)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (int)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Int32[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddInt32(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, Int32[] result, [CallerMemberName] string method = "") + { + Int32[] inArray1 = new Int32[ElementCount]; + Int32[] inArray2 = new Int32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int32[] left, Int32[] right, Int32[] result, [CallerMemberName] string method = "") + { + if ((int)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((int)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int64.cs new file mode 100644 index 0000000..828c4c9 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.Int64.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddInt64() + { + var test = new SimpleBinaryOpTest__AddInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddInt64 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(Int64); + + private static Int64[] _data1 = new Int64[ElementCount]; + private static Int64[] _data2 = new Int64[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (long)(random.Next(int.MinValue, int.MaxValue)); _data2[i] = (long)(random.Next(int.MinValue, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new Int64[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddInt64(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, Int64[] result, [CallerMemberName] string method = "") + { + Int64[] inArray1 = new Int64[ElementCount]; + Int64[] inArray2 = new Int64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(Int64[] left, Int64[] right, Int64[] result, [CallerMemberName] string method = "") + { + if ((long)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((long)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.SByte.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.SByte.cs new file mode 100644 index 0000000..e3ffcc0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.SByte.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddSByte() + { + var test = new SimpleBinaryOpTest__AddSByte(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddSByte + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(SByte); + + private static SByte[] _data1 = new SByte[ElementCount]; + private static SByte[] _data2 = new SByte[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddSByte() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddSByte() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); _data2[i] = (sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new SByte[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddSByte(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, SByte[] result, [CallerMemberName] string method = "") + { + SByte[] inArray1 = new SByte[ElementCount]; + SByte[] inArray2 = new SByte[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(SByte[] left, SByte[] right, SByte[] result, [CallerMemberName] string method = "") + { + if ((sbyte)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((sbyte)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt16.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt16.cs new file mode 100644 index 0000000..ec71b11 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt16.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddUInt16() + { + var test = new SimpleBinaryOpTest__AddUInt16(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddUInt16 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(UInt16); + + private static UInt16[] _data1 = new UInt16[ElementCount]; + private static UInt16[] _data2 = new UInt16[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddUInt16() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddUInt16() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ushort)(random.Next(0, ushort.MaxValue)); _data2[i] = (ushort)(random.Next(0, ushort.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new UInt16[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddUInt16(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, UInt16[] result, [CallerMemberName] string method = "") + { + UInt16[] inArray1 = new UInt16[ElementCount]; + UInt16[] inArray2 = new UInt16[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt16[] left, UInt16[] right, UInt16[] result, [CallerMemberName] string method = "") + { + if ((ushort)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ushort)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt32.cs new file mode 100644 index 0000000..6b52988 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt32.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddUInt32() + { + var test = new SimpleBinaryOpTest__AddUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddUInt32 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(UInt32); + + private static UInt32[] _data1 = new UInt32[ElementCount]; + private static UInt32[] _data2 = new UInt32[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddUInt32() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddUInt32() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (uint)(random.Next(0, int.MaxValue)); _data2[i] = (uint)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new UInt32[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddUInt32(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, UInt32[] result, [CallerMemberName] string method = "") + { + UInt32[] inArray1 = new UInt32[ElementCount]; + UInt32[] inArray2 = new UInt32[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt32[] left, UInt32[] right, UInt32[] result, [CallerMemberName] string method = "") + { + if ((uint)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((uint)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt64.cs new file mode 100644 index 0000000..6ddab32 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add.UInt64.cs @@ -0,0 +1,209 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + private static void AddUInt64() + { + var test = new SimpleBinaryOpTest__AddUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works + test.RunBasicScenario(); + + // Validates calling via reflection works + test.RunReflectionScenario(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works + test.RunLclVarScenario(); + + // Validates passing the field of a local works + test.RunLclFldScenario(); + + // Validates passing an instance member works + test.RunFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class SimpleBinaryOpTest__AddUInt64 + { + private const int VectorSize = 32; + private const int ElementCount = VectorSize / sizeof(UInt64); + + private static UInt64[] _data1 = new UInt64[ElementCount]; + private static UInt64[] _data2 = new UInt64[ElementCount]; + + private static Vector256 _clsVar1; + private static Vector256 _clsVar2; + + private Vector256 _fld1; + private Vector256 _fld2; + + private SimpleBinaryOpTest__DataTable _dataTable; + + static SimpleBinaryOpTest__AddUInt64() + { + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data2[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar2), ref Unsafe.As(ref _data1[0]), VectorSize); + } + + public SimpleBinaryOpTest__AddUInt64() + { + Succeeded = true; + + var random = new Random(); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), VectorSize); + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld2), ref Unsafe.As(ref _data2[0]), VectorSize); + + for (var i = 0; i < ElementCount; i++) { _data1[i] = (ulong)(random.Next(0, int.MaxValue)); _data2[i] = (ulong)(random.Next(0, int.MaxValue)); } + _dataTable = new SimpleBinaryOpTest__DataTable(_data1, _data2, new UInt64[ElementCount]); + } + + public bool IsSupported => Avx2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario() + { + var result = Avx2.Add( + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunReflectionScenario() + { + var result = typeof(Avx2).GetMethod(nameof(Avx2.Add), new Type[] { typeof(Vector256), typeof(Vector256) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr), + Unsafe.Read>(_dataTable.inArray2Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector256)(result)); + ValidateResult(_dataTable.inArray1, _dataTable.inArray2, _dataTable.outArray); + } + + public void RunClsVarScenario() + { + var result = Avx2.Add( + _clsVar1, + _clsVar2 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _clsVar2, _dataTable.outArray); + } + + public void RunLclVarScenario() + { + var left = Unsafe.Read>(_dataTable.inArray1Ptr); + var right = Unsafe.Read>(_dataTable.inArray2Ptr); + var result = Avx2.Add(left, right); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(left, right, _dataTable.outArray); + } + + public void RunLclFldScenario() + { + var test = new SimpleBinaryOpTest__AddUInt64(); + var result = Avx2.Add(test._fld1, test._fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, test._fld2, _dataTable.outArray); + } + + public void RunFldScenario() + { + var result = Avx2.Add(_fld1, _fld2); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _fld2, _dataTable.outArray); + } + + public void RunUnsupportedScenario() + { + Succeeded = false; + + try + { + RunBasicScenario(); + } + catch (PlatformNotSupportedException) + { + Succeeded = true; + } + } + + private void ValidateResult(Vector256 left, Vector256 right, UInt64[] result, [CallerMemberName] string method = "") + { + UInt64[] inArray1 = new UInt64[ElementCount]; + UInt64[] inArray2 = new UInt64[ElementCount]; + + Unsafe.Write(Unsafe.AsPointer(ref inArray1[0]), left); + Unsafe.Write(Unsafe.AsPointer(ref inArray2[0]), right); + + ValidateResult(inArray1, inArray2, result, method); + } + + private void ValidateResult(UInt64[] left, UInt64[] right, UInt64[] result, [CallerMemberName] string method = "") + { + if ((ulong)(left[0] + right[0]) != result[0]) + { + Succeeded = false; + } + else + { + for (var i = 1; i < left.Length; i++) + { + if ((ulong)(left[i] + right[i]) != result[i]) + { + Succeeded = false; + break; + } + } + } + + if (!Succeeded) + { + Console.WriteLine($"{nameof(Avx2)}.{nameof(Avx2.Add)}: {method} failed:"); + Console.WriteLine($" left: ({string.Join(", ", left)})"); + Console.WriteLine($" right: ({string.Join(", ", right)})"); + Console.WriteLine($" result: ({string.Join(", ", result)})"); + Console.WriteLine(); + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj similarity index 79% rename from tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_r.csproj rename to tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj index 376806f..ddf8658 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_r.csproj @@ -27,7 +27,17 @@ - + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj similarity index 79% rename from tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_ro.csproj rename to tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj index 0b1b518..531516b 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Add_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Avx2_ro.csproj @@ -27,7 +27,17 @@ - + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs new file mode 100644 index 0000000..c80c22b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Avx2/Program.Avx2.cs @@ -0,0 +1,26 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. +// See the LICENSE file in the project root for more information. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary() { + ["Add.Byte"] = AddByte, + ["Add.Int16"] = AddInt16, + ["Add.Int32"] = AddInt32, + ["Add.Int64"] = AddInt64, + ["Add.SByte"] = AddSByte, + ["Add.UInt16"] = AddUInt16, + ["Add.UInt32"] = AddUInt32, + ["Add.UInt64"] = AddUInt64, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index ab60f27..58a1f37 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -31,6 +31,19 @@ private static readonly (string templateFileName, string[] templateData)[] AvxIn ("SimpleBinOpTest.template", new string[] { "Avx", "Multiply", "Single", "Vector256", "32", "(float)(random.NextDouble())", "BitConverter.SingleToInt32Bits(left[0] * right[0]) != BitConverter.SingleToInt32Bits(result[0])", "BitConverter.SingleToInt32Bits(left[i] * right[i]) != BitConverter.SingleToInt32Bits(result[i])"}), }; +private static readonly (string templateFileName, string[] templateData)[] Avx2Inputs = new [] +{ + // TemplateName Isa, Method, BaseType, VectorType, VectorSize, NextValue, ValidateFirstResult, ValidateRemainingResults + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Byte", "Vector256", "32", "(byte)(random.Next(0, byte.MaxValue))", "(byte)(left[0] + right[0]) != result[0]", "(byte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int16", "Vector256", "32", "(short)(random.Next(short.MinValue, short.MaxValue))", "(short)(left[0] + right[0]) != result[0]", "(short)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int32", "Vector256", "32", "(int)(random.Next(int.MinValue, int.MaxValue))", "(int)(left[0] + right[0]) != result[0]", "(int)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "Int64", "Vector256", "32", "(long)(random.Next(int.MinValue, int.MaxValue))", "(long)(left[0] + right[0]) != result[0]", "(long)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "SByte", "Vector256", "32", "(sbyte)(random.Next(sbyte.MinValue, sbyte.MaxValue))", "(sbyte)(left[0] + right[0]) != result[0]", "(sbyte)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt16", "Vector256", "32", "(ushort)(random.Next(0, ushort.MaxValue))", "(ushort)(left[0] + right[0]) != result[0]", "(ushort)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt32", "Vector256", "32", "(uint)(random.Next(0, int.MaxValue))", "(uint)(left[0] + right[0]) != result[0]", "(uint)(left[i] + right[i]) != result[i]"}), + ("SimpleBinOpTest.template", new string[] { "Avx2", "Add", "UInt64", "Vector256", "32", "(ulong)(random.Next(0, int.MaxValue))", "(ulong)(left[0] + right[0]) != result[0]", "(ulong)(left[i] + right[i]) != result[i]"}), +}; + private static void ProcessInputs(string isa, (string templateFileName, string[] templateData)[] inputs) { var testListFileName = Path.Combine("..", isa, $"Program.{isa}.cs"); @@ -84,3 +97,4 @@ private static void ProcessInput(StreamWriter testListFile, (string templateFile ProcessInputs("Sse2", Sse2Inputs); ProcessInputs("Avx", AvxInputs); +ProcessInputs("Avx2", Avx2Inputs); -- 2.7.4