From b4a56b0339ff1eea904e1b8d3f89507552529d3b Mon Sep 17 00:00:00 2001 From: Tanner Gooding Date: Wed, 7 Aug 2019 09:15:29 -0700 Subject: Ensure that we check for implicit ivals for single argument intrinsics before the SIMDScalar handling. (#25905) (#25987) * Ensure that we check for implicit ivals for single argument intrinsics before the SIMDScalar handling. * Adding test template entries for the unary overloads of the Sse41.Round functions * Regenerating the hardware intrinsic test templates. --- .../X86/Shared/GenerateTests.csx | 13 + .../Sse41_Overloaded/Program.Sse41_Overloaded.cs | 26 + .../RoundCurrentDirectionScalar.Double.cs | 541 +++++++++++++++++++++ .../RoundCurrentDirectionScalar.Single.cs | 541 +++++++++++++++++++++ .../RoundToNearestIntegerScalar.Double.cs | 541 +++++++++++++++++++++ .../RoundToNearestIntegerScalar.Single.cs | 541 +++++++++++++++++++++ .../RoundToNegativeInfinityScalar.Double.cs | 541 +++++++++++++++++++++ .../RoundToNegativeInfinityScalar.Single.cs | 541 +++++++++++++++++++++ .../RoundToPositiveInfinityScalar.Double.cs | 541 +++++++++++++++++++++ .../RoundToPositiveInfinityScalar.Single.cs | 541 +++++++++++++++++++++ .../X86/Sse41_Overloaded/Sse41_Overloaded_r.csproj | 44 ++ .../Sse41_Overloaded/Sse41_Overloaded_ro.csproj | 44 ++ 12 files changed, 4455 insertions(+) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Program.Sse41_Overloaded.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Double.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Single.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_r.csproj create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_ro.csproj (limited to 'tests/src/JIT') diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 853681c651..174d4e5606 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -598,6 +598,18 @@ private static readonly (string templateFileName, Dictionary tem ("BooleanBinOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse2", ["Method"] = "TestZ", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "UInt64", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "UInt64", ["Op2VectorType"] = "Vector128", ["Op2BaseType"] = "UInt64", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateFirstResult"] = "(left[i] & right[i]) == 0"}), }; +private static readonly (string templateFileName, Dictionary templateData)[] Sse41_OverloadedInputs = new [] +{ + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse2", ["Method"] = "RoundCurrentDirectionScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse", ["Method"] = "RoundCurrentDirectionScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse2", ["Method"] = "RoundToNearestIntegerScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse", ["Method"] = "RoundToNearestIntegerScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0], MidpointRounding.AwayFromZero))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse2", ["Method"] = "RoundToNegativeInfinityScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse", ["Method"] = "RoundToNegativeInfinityScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse2", ["Method"] = "RoundToPositiveInfinityScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Double", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Double", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetDouble()", ["ValidateFirstResult"] = "BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])"}), + ("SimpleUnOpTest.template", new Dictionary { ["Isa"] = "Sse41", ["LoadIsa"] = "Sse", ["Method"] = "RoundToPositiveInfinityScalar", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Single", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Single", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetSingle()", ["ValidateFirstResult"] = "BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))", ["ValidateRemainingResults"] = "BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])"}), +}; + private static readonly (string templateFileName, Dictionary templateData)[] Sse41X64Inputs = new [] { ("ExtractScalarTest.template", new Dictionary { ["Isa"] = "Sse41.X64", ["LoadIsa"] = "Sse2", ["Method"] = "Extract", ["RetVectorType"] = "Vector128", ["RetBaseType"] = "Int64", ["Op1VectorType"] ="Vector128", ["Op1BaseType"] = "Int64", ["Imm"] = "129", ["LargestVectorSize"] = "16", ["NextValueOp1"] = "TestLibrary.Generator.GetInt64()", ["ValidateFirstResult"] = "(result[0] != firstOp[1])"}), @@ -1349,6 +1361,7 @@ ProcessInputs("Sse2.X64", Sse2X64Inputs); ProcessInputs("Sse3", Sse3Inputs); ProcessInputs("Ssse3", Ssse3Inputs); ProcessInputs("Sse41", Sse41Inputs); +ProcessInputs("Sse41_Overloaded", Sse41_OverloadedInputs); ProcessInputs("Sse41.X64", Sse41X64Inputs); ProcessInputs("Sse42", Sse42Inputs); ProcessInputs("Avx", AvxInputs); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Program.Sse41_Overloaded.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Program.Sse41_Overloaded.cs new file mode 100644 index 0000000000..9a3a4a58e7 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Program.Sse41_Overloaded.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() { + ["RoundCurrentDirectionScalar.Double"] = RoundCurrentDirectionScalarDouble, + ["RoundCurrentDirectionScalar.Single"] = RoundCurrentDirectionScalarSingle, + ["RoundToNearestIntegerScalar.Double"] = RoundToNearestIntegerScalarDouble, + ["RoundToNearestIntegerScalar.Single"] = RoundToNearestIntegerScalarSingle, + ["RoundToNegativeInfinityScalar.Double"] = RoundToNegativeInfinityScalarDouble, + ["RoundToNegativeInfinityScalar.Single"] = RoundToNegativeInfinityScalarSingle, + ["RoundToPositiveInfinityScalar.Double"] = RoundToPositiveInfinityScalarDouble, + ["RoundToPositiveInfinityScalar.Single"] = RoundToPositiveInfinityScalarSingle, + }; + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Double.cs new file mode 100644 index 0000000000..bde4a737df --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Double.cs @@ -0,0 +1,541 @@ +// 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 RoundCurrentDirectionScalarDouble() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble(); + + 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(); + + if (Sse2.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // 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(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundCurrentDirectionScalarDouble + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble testClass) + { + var result = Sse41.RoundCurrentDirectionScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[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.RoundCurrentDirectionScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundCurrentDirectionScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarDouble(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundCurrentDirectionScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundCurrentDirectionScalar( + Sse2.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirectionScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Single.cs new file mode 100644 index 0000000000..132067fa24 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundCurrentDirectionScalar.Single.cs @@ -0,0 +1,541 @@ +// 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 RoundCurrentDirectionScalarSingle() + { + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundCurrentDirectionScalarSingle + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle testClass) + { + var result = Sse41.RoundCurrentDirectionScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[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.RoundCurrentDirectionScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundCurrentDirectionScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundCurrentDirectionScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundCurrentDirectionScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundCurrentDirectionScalarSingle(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundCurrentDirectionScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundCurrentDirectionScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundCurrentDirectionScalar( + Sse.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundCurrentDirectionScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Double.cs new file mode 100644 index 0000000000..3192fcd1f4 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Double.cs @@ -0,0 +1,541 @@ +// 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 RoundToNearestIntegerScalarDouble() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble(); + + 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(); + + if (Sse2.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // 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(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToNearestIntegerScalarDouble + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble testClass) + { + var result = Sse41.RoundToNearestIntegerScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[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.RoundToNearestIntegerScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToNearestIntegerScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarDouble(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToNearestIntegerScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNearestIntegerScalar( + Sse2.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Round(firstOp[0], MidpointRounding.AwayFromZero))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestIntegerScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Single.cs new file mode 100644 index 0000000000..c79699c69b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNearestIntegerScalar.Single.cs @@ -0,0 +1,541 @@ +// 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 RoundToNearestIntegerScalarSingle() + { + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToNearestIntegerScalarSingle + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle testClass) + { + var result = Sse41.RoundToNearestIntegerScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[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.RoundToNearestIntegerScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNearestIntegerScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToNearestIntegerScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNearestIntegerScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToNearestIntegerScalarSingle(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToNearestIntegerScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNearestIntegerScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNearestIntegerScalar( + Sse.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Round(firstOp[0], MidpointRounding.AwayFromZero))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToNearestIntegerScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Double.cs new file mode 100644 index 0000000000..42d0c1a706 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Double.cs @@ -0,0 +1,541 @@ +// 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 RoundToNegativeInfinityScalarDouble() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble(); + + 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(); + + if (Sse2.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // 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(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToNegativeInfinityScalarDouble + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble testClass) + { + var result = Sse41.RoundToNegativeInfinityScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[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.RoundToNegativeInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToNegativeInfinityScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarDouble(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToNegativeInfinityScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNegativeInfinityScalar( + Sse2.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Floor(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinityScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Single.cs new file mode 100644 index 0000000000..b8268d82fe --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToNegativeInfinityScalar.Single.cs @@ -0,0 +1,541 @@ +// 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 RoundToNegativeInfinityScalarSingle() + { + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToNegativeInfinityScalarSingle + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle testClass) + { + var result = Sse41.RoundToNegativeInfinityScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[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.RoundToNegativeInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToNegativeInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToNegativeInfinityScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToNegativeInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToNegativeInfinityScalarSingle(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToNegativeInfinityScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNegativeInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToNegativeInfinityScalar( + Sse.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Floor(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToNegativeInfinityScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Double.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Double.cs new file mode 100644 index 0000000000..22e23d4d6a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Double.cs @@ -0,0 +1,541 @@ +// 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 RoundToPositiveInfinityScalarDouble() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble(); + + 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(); + + if (Sse2.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // 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(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse2.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToPositiveInfinityScalarDouble + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Double[] inArray1, Double[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble testClass) + { + var result = Sse41.RoundToPositiveInfinityScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Double); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Double); + + private static Double[] _data1 = new Double[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetDouble(); } + _dataTable = new DataTable(_data1, new Double[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.RoundToPositiveInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToPositiveInfinityScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse2.LoadVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse2.LoadAlignedVector128((Double*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarDouble(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToPositiveInfinityScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToPositiveInfinityScalar( + Sse2.LoadVector128((Double*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Double[] inArray1 = new Double[Op1ElementCount]; + Double[] outArray = new Double[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Double[] firstOp, Double[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.DoubleToInt64Bits(result[0]) != BitConverter.DoubleToInt64Bits(Math.Ceiling(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.DoubleToInt64Bits(result[i]) != BitConverter.DoubleToInt64Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinityScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Single.cs b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Single.cs new file mode 100644 index 0000000000..eeae99793d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/RoundToPositiveInfinityScalar.Single.cs @@ -0,0 +1,541 @@ +// 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 RoundToPositiveInfinityScalarSingle() + { + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.Read + test.RunBasicScenario_UnsafeRead(); + + if (Sse.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 (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing a static member works, using pinning and Load + test.RunClsVarScenario_Load(); + } + + // Validates passing a local works, using Unsafe.Read + test.RunLclVarScenario_UnsafeRead(); + + if (Sse.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(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local class works, using pinning and Load + test.RunClassLclFldScenario_Load(); + } + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a class works, using pinning and Load + test.RunClassFldScenario_Load(); + } + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing the field of a local struct works, using pinning and Load + test.RunStructLclFldScenario_Load(); + } + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + + if (Sse.IsSupported) + { + // Validates passing an instance member of a struct works, using pinning and Load + test.RunStructFldScenario_Load(); + } + } + 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__RoundToPositiveInfinityScalarSingle + { + private struct DataTable + { + private byte[] inArray1; + private byte[] outArray; + + private GCHandle inHandle1; + private GCHandle outHandle; + + private ulong alignment; + + public DataTable(Single[] inArray1, Single[] outArray, int alignment) + { + int sizeOfinArray1 = inArray1.Length * Unsafe.SizeOf(); + int sizeOfoutArray = outArray.Length * Unsafe.SizeOf(); + if ((alignment != 32 && alignment != 16) || (alignment * 2) < sizeOfinArray1 || (alignment * 2) < sizeOfoutArray) + { + throw new ArgumentException("Invalid value of alignment"); + } + + this.inArray1 = new byte[alignment * 2]; + this.outArray = new byte[alignment * 2]; + + this.inHandle1 = GCHandle.Alloc(this.inArray1, GCHandleType.Pinned); + this.outHandle = GCHandle.Alloc(this.outArray, GCHandleType.Pinned); + + this.alignment = (ulong)alignment; + + Unsafe.CopyBlockUnaligned(ref Unsafe.AsRef(inArray1Ptr), ref Unsafe.As(ref inArray1[0]), (uint)sizeOfinArray1); + } + + public void* inArray1Ptr => Align((byte*)(inHandle1.AddrOfPinnedObject().ToPointer()), alignment); + public void* outArrayPtr => Align((byte*)(outHandle.AddrOfPinnedObject().ToPointer()), alignment); + + public void Dispose() + { + inHandle1.Free(); + outHandle.Free(); + } + + private static unsafe void* Align(byte* buffer, ulong expectedAlignment) + { + return (void*)(((ulong)buffer + expectedAlignment - 1) & ~(expectedAlignment - 1)); + } + } + + private struct TestStruct + { + public Vector128 _fld1; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref testStruct._fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + return testStruct; + } + + public void RunStructFldScenario(SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle testClass) + { + var result = Sse41.RoundToPositiveInfinityScalar(_fld1); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + + public void RunStructFldScenario_Load(SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle testClass) + { + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(testClass._dataTable.outArrayPtr, result); + testClass.ValidateResult(_fld1, testClass._dataTable.outArrayPtr); + } + } + } + + private static readonly int LargestVectorSize = 16; + + private static readonly int Op1ElementCount = Unsafe.SizeOf>() / sizeof(Single); + private static readonly int RetElementCount = Unsafe.SizeOf>() / sizeof(Single); + + private static Single[] _data1 = new Single[Op1ElementCount]; + + private static Vector128 _clsVar1; + + private Vector128 _fld1; + + private DataTable _dataTable; + + static SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle() + { + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _clsVar1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + } + + public SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle() + { + Succeeded = true; + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + Unsafe.CopyBlockUnaligned(ref Unsafe.As, byte>(ref _fld1), ref Unsafe.As(ref _data1[0]), (uint)Unsafe.SizeOf>()); + + for (var i = 0; i < Op1ElementCount; i++) { _data1[i] = TestLibrary.Generator.GetSingle(); } + _dataTable = new DataTable(_data1, new Single[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.RoundToPositiveInfinityScalar( + Unsafe.Read>(_dataTable.inArray1Ptr) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_Load)); + + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunBasicScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_LoadAligned)); + + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Unsafe.Read>(_dataTable.inArray1Ptr) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_Load)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunReflectionScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_LoadAligned)); + + var result = typeof(Sse41).GetMethod(nameof(Sse41.RoundToPositiveInfinityScalar), new Type[] { typeof(Vector128) }) + .Invoke(null, new object[] { + Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)) + }); + + Unsafe.Write(_dataTable.outArrayPtr, (Vector128)(result)); + ValidateResult(_dataTable.inArray1Ptr, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Sse41.RoundToPositiveInfinityScalar( + _clsVar1 + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + + public void RunClsVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario_Load)); + + fixed (Vector128* pClsVar1 = &_clsVar1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(pClsVar1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_clsVar1, _dataTable.outArrayPtr); + } + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var op1 = Unsafe.Read>(_dataTable.inArray1Ptr); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_Load)); + + var op1 = Sse.LoadVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunLclVarScenario_LoadAligned() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_LoadAligned)); + + var op1 = Sse.LoadAlignedVector128((Single*)(_dataTable.inArray1Ptr)); + var result = Sse41.RoundToPositiveInfinityScalar(op1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(op1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunClassLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario_Load)); + + var test = new SimpleUnaryOpTest__RoundToPositiveInfinityScalarSingle(); + + fixed (Vector128* pFld1 = &test._fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Sse41.RoundToPositiveInfinityScalar(_fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + + public void RunClassFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario_Load)); + + fixed (Vector128* pFld1 = &_fld1) + { + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(pFld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(_fld1, _dataTable.outArrayPtr); + } + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToPositiveInfinityScalar(test._fld1); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructLclFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario_Load)); + + var test = TestStruct.Create(); + var result = Sse41.RoundToPositiveInfinityScalar( + Sse.LoadVector128((Single*)(&test._fld1)) + ); + + Unsafe.Write(_dataTable.outArrayPtr, result); + ValidateResult(test._fld1, _dataTable.outArrayPtr); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(this); + } + + public void RunStructFldScenario_Load() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario_Load)); + + var test = TestStruct.Create(); + test.RunStructFldScenario_Load(this); + } + + public void RunUnsupportedScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunUnsupportedScenario)); + + bool succeeded = false; + + try + { + RunBasicScenario_UnsafeRead(); + } + catch (PlatformNotSupportedException) + { + succeeded = true; + } + + if (!succeeded) + { + Succeeded = false; + } + } + + private void ValidateResult(Vector128 op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.WriteUnaligned(ref Unsafe.As(ref inArray1[0]), op1); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(void* op1, void* result, [CallerMemberName] string method = "") + { + Single[] inArray1 = new Single[Op1ElementCount]; + Single[] outArray = new Single[RetElementCount]; + + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref inArray1[0]), ref Unsafe.AsRef(op1), (uint)Unsafe.SizeOf>()); + Unsafe.CopyBlockUnaligned(ref Unsafe.As(ref outArray[0]), ref Unsafe.AsRef(result), (uint)Unsafe.SizeOf>()); + + ValidateResult(inArray1, outArray, method); + } + + private void ValidateResult(Single[] firstOp, Single[] result, [CallerMemberName] string method = "") + { + bool succeeded = true; + + if (BitConverter.SingleToInt32Bits(result[0]) != BitConverter.SingleToInt32Bits(MathF.Ceiling(firstOp[0]))) + { + succeeded = false; + } + else + { + for (var i = 1; i < RetElementCount; i++) + { + if (BitConverter.SingleToInt32Bits(result[i]) != BitConverter.SingleToInt32Bits(firstOp[i])) + { + succeeded = false; + break; + } + } + } + + if (!succeeded) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Sse41)}.{nameof(Sse41.RoundToPositiveInfinityScalar)}(Vector128): {method} failed:"); + TestLibrary.TestFramework.LogInformation($" firstOp: ({string.Join(", ", firstOp)})"); + TestLibrary.TestFramework.LogInformation($" result: ({string.Join(", ", result)})"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_r.csproj new file mode 100644 index 0000000000..bf69d5637a --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_r.csproj @@ -0,0 +1,44 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + Embedded + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_ro.csproj new file mode 100644 index 0000000000..a4ed64554d --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Sse41_Overloaded/Sse41_Overloaded_ro.csproj @@ -0,0 +1,44 @@ + + + + + Debug + AnyCPU + 2.0 + {95DFC527-4DC1-495E-97D7-E94EE1F7140D} + Exe + {786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC} + ..\..\ + true + + + + + + + False + + + + Embedded + True + + + + + + + + + + + + + + + + + + + + -- cgit v1.2.3