From 7ac4a46d1528484e38e4c808d8a0bbe1b715e0d2 Mon Sep 17 00:00:00 2001 From: Fei Peng Date: Fri, 21 Dec 2018 07:14:08 -0800 Subject: Implement the remaining BMI1/2 intrinsic (#21480) * Add tests for BMI1/2 intrinsic * Implement the remaining BMI1/2 intrinsic * Fix emitDispIns for BMI instruction --- .../X86/Bmi1.X64/BitFieldExtract.UInt64.3Op.cs | 255 ++++++++++++++++++++ .../X86/Bmi1.X64/BitFieldExtract.UInt64.cs | 242 +++++++++++++++++++ .../X86/Bmi1.X64/Bmi1.X64_r.csproj | 2 + .../X86/Bmi1.X64/Bmi1.X64_ro.csproj | 2 + .../X86/Bmi1.X64/Program.Bmi1.X64.cs | 2 + .../X86/Bmi1/BitFieldExtract.UInt32.3Op.cs | 255 ++++++++++++++++++++ .../X86/Bmi1/BitFieldExtract.UInt32.cs | 242 +++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_r.csproj | 2 + .../JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_ro.csproj | 2 + .../HardwareIntrinsics/X86/Bmi1/Program.Bmi1.cs | 2 + .../X86/Bmi2.X64/Bmi2.X64_r.csproj | 3 + .../X86/Bmi2.X64/Bmi2.X64_ro.csproj | 3 + .../X86/Bmi2.X64/MultiplyNoFlags.UInt64.BinRes.cs | 265 +++++++++++++++++++++ .../X86/Bmi2.X64/MultiplyNoFlags.UInt64.cs | 242 +++++++++++++++++++ .../X86/Bmi2.X64/Program.Bmi2.X64.cs | 3 + .../X86/Bmi2.X64/ZeroHighBits.UInt64.cs | 242 +++++++++++++++++++ .../JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_r.csproj | 3 + .../JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_ro.csproj | 3 + .../X86/Bmi2/MultiplyNoFlags.UInt32.BinRes.cs | 265 +++++++++++++++++++++ .../X86/Bmi2/MultiplyNoFlags.UInt32.cs | 242 +++++++++++++++++++ .../HardwareIntrinsics/X86/Bmi2/Program.Bmi2.cs | 3 + .../X86/Bmi2/ZeroHighBits.UInt32.cs | 242 +++++++++++++++++++ .../X86/Shared/GenerateTests.csx | 48 ++-- .../X86/Shared/ScalarBinOpTest.template | 2 +- .../X86/Shared/ScalarTernOpBinResTest.template | 265 +++++++++++++++++++++ .../X86/Shared/ScalarTernOpTest.template | 255 ++++++++++++++++++++ 26 files changed, 3077 insertions(+), 15 deletions(-) create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.3Op.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.3Op.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.BinRes.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/ZeroHighBits.UInt64.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.BinRes.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Bmi2/ZeroHighBits.UInt32.cs create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpBinResTest.template create mode 100644 tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTest.template (limited to 'tests') diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.3Op.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.3Op.cs new file mode 100644 index 0000000000..a6bf026bc8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.3Op.cs @@ -0,0 +1,255 @@ +// 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 BitFieldExtractUInt643Op() + { + var test = new ScalarTernOpTest__BitFieldExtractUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpTest__BitFieldExtractUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public Byte _fld2; + public Byte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0x1E00000000000000; + testStruct._fld2 = 57; + testStruct._fld3 = 4; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTest__BitFieldExtractUInt64 testClass) + { + var result = Bmi1.X64.BitFieldExtract(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static UInt64 _data1; + private static Byte _data2; + private static Byte _data3; + + private static UInt64 _clsVar1; + private static Byte _clsVar2; + private static Byte _clsVar3; + + private UInt64 _fld1; + private Byte _fld2; + private Byte _fld3; + + static ScalarTernOpTest__BitFieldExtractUInt64() + { + _clsVar1 = 0x1E00000000000000; + _clsVar2 = 57; + _clsVar3 = 4; + } + + public ScalarTernOpTest__BitFieldExtractUInt64() + { + Succeeded = true; + + _fld1 = 0x1E00000000000000; + _fld2 = 57; + _fld3 = 4; + + _data1 = 0x1E00000000000000; + _data2 = 57; + _data3 = 4; + } + + public bool IsSupported => Bmi1.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi1.X64.BitFieldExtract( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + ); + + ValidateResult(_data1, _data2, _data3, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi1.X64).GetMethod(nameof(Bmi1.X64.BitFieldExtract), new Type[] { typeof(UInt64), typeof(Byte), typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + }); + + ValidateResult(_data1, _data2, _data3, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi1.X64.BitFieldExtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + ValidateResult(_clsVar1, _clsVar2, _clsVar3, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var data3 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)); + var result = Bmi1.X64.BitFieldExtract(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTest__BitFieldExtractUInt64(); + var result = Bmi1.X64.BitFieldExtract(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi1.X64.BitFieldExtract(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi1.X64.BitFieldExtract(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt64 op1, Byte op2, Byte op3, UInt64 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + ulong expectedResult = 15; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi1.X64)}.{nameof(Bmi1.X64.BitFieldExtract)}(UInt64, Byte, Byte): BitFieldExtract failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.cs new file mode 100644 index 0000000000..1e97d01a26 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/BitFieldExtract.UInt64.cs @@ -0,0 +1,242 @@ +// 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 BitFieldExtractUInt64() + { + var test = new ScalarBinaryOpTest__BitFieldExtractUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__BitFieldExtractUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public UInt16 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0x1E00000000000000; + testStruct._fld2 = 0x0439; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__BitFieldExtractUInt64 testClass) + { + var result = Bmi1.X64.BitFieldExtract(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt64 _data1; + private static UInt16 _data2; + + private static UInt64 _clsVar1; + private static UInt16 _clsVar2; + + private UInt64 _fld1; + private UInt16 _fld2; + + static ScalarBinaryOpTest__BitFieldExtractUInt64() + { + _clsVar1 = 0x1E00000000000000; + _clsVar2 = 0x0439; + } + + public ScalarBinaryOpTest__BitFieldExtractUInt64() + { + Succeeded = true; + + _fld1 = 0x1E00000000000000; + _fld2 = 0x0439; + + _data1 = 0x1E00000000000000; + _data2 = 0x0439; + } + + public bool IsSupported => Bmi1.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi1.X64.BitFieldExtract( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi1.X64).GetMethod(nameof(Bmi1.X64.BitFieldExtract), new Type[] { typeof(UInt64), typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi1.X64.BitFieldExtract( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi1.X64.BitFieldExtract(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__BitFieldExtractUInt64(); + var result = Bmi1.X64.BitFieldExtract(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi1.X64.BitFieldExtract(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi1.X64.BitFieldExtract(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt64 left, UInt16 right, UInt64 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + ulong expectedResult = 15; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi1.X64)}.{nameof(Bmi1.X64.BitFieldExtract)}(UInt64, UInt16): BitFieldExtract failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_r.csproj index 9e70b4ed56..1d51fa0478 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_r.csproj @@ -32,6 +32,8 @@ + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_ro.csproj index 464299846a..6617feda98 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Bmi1.X64_ro.csproj @@ -32,6 +32,8 @@ + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Program.Bmi1.X64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Program.Bmi1.X64.cs index ce22b997ec..a37b7897b8 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Program.Bmi1.X64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1.X64/Program.Bmi1.X64.cs @@ -17,6 +17,8 @@ namespace JIT.HardwareIntrinsics.X86 ["GetMaskUpToLowestSetBit.UInt64"] = GetMaskUpToLowestSetBitUInt64, ["ResetLowestSetBit.UInt64"] = ResetLowestSetBitUInt64, ["TrailingZeroCount.UInt64"] = TrailingZeroCountUInt64, + ["BitFieldExtract.UInt64.3Op"] = BitFieldExtractUInt643Op, + ["BitFieldExtract.UInt64"] = BitFieldExtractUInt64, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.3Op.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.3Op.cs new file mode 100644 index 0000000000..c93b643747 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.3Op.cs @@ -0,0 +1,255 @@ +// 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 BitFieldExtractUInt323Op() + { + var test = new ScalarTernOpTest__BitFieldExtractUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpTest__BitFieldExtractUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public Byte _fld2; + public Byte _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0x1E000000; + testStruct._fld2 = 25; + testStruct._fld3 = 4; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTest__BitFieldExtractUInt32 testClass) + { + var result = Bmi1.BitFieldExtract(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static UInt32 _data1; + private static Byte _data2; + private static Byte _data3; + + private static UInt32 _clsVar1; + private static Byte _clsVar2; + private static Byte _clsVar3; + + private UInt32 _fld1; + private Byte _fld2; + private Byte _fld3; + + static ScalarTernOpTest__BitFieldExtractUInt32() + { + _clsVar1 = 0x1E000000; + _clsVar2 = 25; + _clsVar3 = 4; + } + + public ScalarTernOpTest__BitFieldExtractUInt32() + { + Succeeded = true; + + _fld1 = 0x1E000000; + _fld2 = 25; + _fld3 = 4; + + _data1 = 0x1E000000; + _data2 = 25; + _data3 = 4; + } + + public bool IsSupported => Bmi1.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi1.BitFieldExtract( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + ); + + ValidateResult(_data1, _data2, _data3, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi1).GetMethod(nameof(Bmi1.BitFieldExtract), new Type[] { typeof(UInt32), typeof(Byte), typeof(Byte) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + }); + + ValidateResult(_data1, _data2, _data3, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi1.BitFieldExtract( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + ValidateResult(_clsVar1, _clsVar2, _clsVar3, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var data3 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)); + var result = Bmi1.BitFieldExtract(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTest__BitFieldExtractUInt32(); + var result = Bmi1.BitFieldExtract(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi1.BitFieldExtract(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi1.BitFieldExtract(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt32 op1, Byte op2, Byte op3, UInt32 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + uint expectedResult = 15; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi1)}.{nameof(Bmi1.BitFieldExtract)}(UInt32, Byte, Byte): BitFieldExtract failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.cs new file mode 100644 index 0000000000..e08e3006b3 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/BitFieldExtract.UInt32.cs @@ -0,0 +1,242 @@ +// 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 BitFieldExtractUInt32() + { + var test = new ScalarBinaryOpTest__BitFieldExtractUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__BitFieldExtractUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public UInt16 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0x1E000000; + testStruct._fld2 = 0x0419; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__BitFieldExtractUInt32 testClass) + { + var result = Bmi1.BitFieldExtract(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt32 _data1; + private static UInt16 _data2; + + private static UInt32 _clsVar1; + private static UInt16 _clsVar2; + + private UInt32 _fld1; + private UInt16 _fld2; + + static ScalarBinaryOpTest__BitFieldExtractUInt32() + { + _clsVar1 = 0x1E000000; + _clsVar2 = 0x0419; + } + + public ScalarBinaryOpTest__BitFieldExtractUInt32() + { + Succeeded = true; + + _fld1 = 0x1E000000; + _fld2 = 0x0419; + + _data1 = 0x1E000000; + _data2 = 0x0419; + } + + public bool IsSupported => Bmi1.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi1.BitFieldExtract( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi1).GetMethod(nameof(Bmi1.BitFieldExtract), new Type[] { typeof(UInt32), typeof(UInt16) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi1.BitFieldExtract( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi1.BitFieldExtract(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__BitFieldExtractUInt32(); + var result = Bmi1.BitFieldExtract(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi1.BitFieldExtract(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi1.BitFieldExtract(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt32 left, UInt16 right, UInt32 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + uint expectedResult = 15; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi1)}.{nameof(Bmi1.BitFieldExtract)}(UInt32, UInt16): BitFieldExtract failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_r.csproj index 4b9346525e..96c2b720fc 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_r.csproj @@ -32,6 +32,8 @@ + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_ro.csproj index 7286ee01b8..856710da6a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Bmi1_ro.csproj @@ -32,6 +32,8 @@ + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Program.Bmi1.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Program.Bmi1.cs index a93c4a5d50..1053bc203a 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Program.Bmi1.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi1/Program.Bmi1.cs @@ -17,6 +17,8 @@ namespace JIT.HardwareIntrinsics.X86 ["GetMaskUpToLowestSetBit.UInt32"] = GetMaskUpToLowestSetBitUInt32, ["ResetLowestSetBit.UInt32"] = ResetLowestSetBitUInt32, ["TrailingZeroCount.UInt32"] = TrailingZeroCountUInt32, + ["BitFieldExtract.UInt32.3Op"] = BitFieldExtractUInt323Op, + ["BitFieldExtract.UInt32"] = BitFieldExtractUInt32, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_r.csproj index e620aa1291..45c6e6c520 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_r.csproj @@ -29,6 +29,9 @@ + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_ro.csproj index 0c28c955c9..a0506e9452 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Bmi2.X64_ro.csproj @@ -29,6 +29,9 @@ + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.BinRes.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.BinRes.cs new file mode 100644 index 0000000000..83529943e0 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.BinRes.cs @@ -0,0 +1,265 @@ +// 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.Reflection; +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 MultiplyNoFlagsUInt64BinRes() + { + var test = new ScalarTernOpBinResTest__MultiplyNoFlagsUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpBinResTest__MultiplyNoFlagsUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public UInt64 _fld2; + public UInt64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt64.MaxValue; + testStruct._fld2 = UInt64.MaxValue; + testStruct._fld3 = 0; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpBinResTest__MultiplyNoFlagsUInt64 testClass) + { + UInt64 buffer = 0; + var result = Bmi2.X64.MultiplyNoFlags(_fld1, _fld2, &buffer); + testClass.ValidateResult(_fld1, _fld2, buffer, result); + } + } + + private static UInt64 _data1; + private static UInt64 _data2; + private static UInt64 _data3; + + private static UInt64 _clsVar1; + private static UInt64 _clsVar2; + private static UInt64 _clsVar3; + + private UInt64 _fld1; + private UInt64 _fld2; + private UInt64 _fld3; + + static ScalarTernOpBinResTest__MultiplyNoFlagsUInt64() + { + _clsVar1 = UInt64.MaxValue; + _clsVar2 = UInt64.MaxValue; + _clsVar3 = 0; + } + + public ScalarTernOpBinResTest__MultiplyNoFlagsUInt64() + { + Succeeded = true; + + _fld1 = UInt64.MaxValue; + _fld2 = UInt64.MaxValue; + _fld3 = 0; + + _data1 = UInt64.MaxValue; + _data2 = UInt64.MaxValue; + _data3 = 0; + } + + public bool IsSupported => Bmi2.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + UInt64 buffer = 0; + + var result = Bmi2.X64.MultiplyNoFlags( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + &buffer + ); + + ValidateResult(_data1, _data2, buffer, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt64 buffer = 0; + + var result = typeof(Bmi2.X64).GetMethod(nameof(Bmi2.X64.MultiplyNoFlags), new Type[] { typeof(UInt64), typeof(UInt64), typeof(UInt64*) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Pointer.Box(&buffer, typeof(UInt64*)) + }); + + ValidateResult(_data1, _data2, buffer, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + UInt64 buffer = 0; + var result = Bmi2.X64.MultiplyNoFlags( + _clsVar1, + _clsVar2, + &buffer + ); + + ValidateResult(_clsVar1, _clsVar2, buffer, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var data3 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)); + var result = Bmi2.X64.MultiplyNoFlags(data1, data2, &data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + UInt64 buffer = 0; + + var test = new ScalarTernOpBinResTest__MultiplyNoFlagsUInt64(); + var result = Bmi2.X64.MultiplyNoFlags(test._fld1, test._fld2, &buffer); + + ValidateResult(test._fld1, test._fld2, buffer, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + UInt64 buffer = 0; + + var result = Bmi2.X64.MultiplyNoFlags(_fld1, _fld2, &buffer); + ValidateResult(_fld1, _fld2, buffer, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.X64.MultiplyNoFlags(test._fld1, test._fld2, &test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt64 op1, UInt64 op2, UInt64 lower, UInt64 higher, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + ulong expectedHigher = 18446744073709551614, expectedLower = 1; isUnexpectedResult = (expectedHigher != higher) || (expectedLower != lower); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2.X64)}.{nameof(Bmi2.X64.MultiplyNoFlags)}(UInt64, UInt64, UInt64): MultiplyNoFlags failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" lower: {lower}"); + TestLibrary.TestFramework.LogInformation($"higher: {higher}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.cs new file mode 100644 index 0000000000..78d5a7e80b --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/MultiplyNoFlags.UInt64.cs @@ -0,0 +1,242 @@ +// 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 MultiplyNoFlagsUInt64() + { + var test = new ScalarBinaryOpTest__MultiplyNoFlagsUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__MultiplyNoFlagsUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public UInt64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt64.MaxValue; + testStruct._fld2 = UInt64.MaxValue; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__MultiplyNoFlagsUInt64 testClass) + { + var result = Bmi2.X64.MultiplyNoFlags(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt64 _data1; + private static UInt64 _data2; + + private static UInt64 _clsVar1; + private static UInt64 _clsVar2; + + private UInt64 _fld1; + private UInt64 _fld2; + + static ScalarBinaryOpTest__MultiplyNoFlagsUInt64() + { + _clsVar1 = UInt64.MaxValue; + _clsVar2 = UInt64.MaxValue; + } + + public ScalarBinaryOpTest__MultiplyNoFlagsUInt64() + { + Succeeded = true; + + _fld1 = UInt64.MaxValue; + _fld2 = UInt64.MaxValue; + + _data1 = UInt64.MaxValue; + _data2 = UInt64.MaxValue; + } + + public bool IsSupported => Bmi2.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi2.X64.MultiplyNoFlags( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi2.X64).GetMethod(nameof(Bmi2.X64.MultiplyNoFlags), new Type[] { typeof(UInt64), typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi2.X64.MultiplyNoFlags( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi2.X64.MultiplyNoFlags(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__MultiplyNoFlagsUInt64(); + var result = Bmi2.X64.MultiplyNoFlags(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi2.X64.MultiplyNoFlags(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.X64.MultiplyNoFlags(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt64 left, UInt64 right, UInt64 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + ulong expectedResult = 18446744073709551614; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2.X64)}.{nameof(Bmi2.X64.MultiplyNoFlags)}(UInt64, UInt64): MultiplyNoFlags failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Program.Bmi2.X64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Program.Bmi2.X64.cs index c0f8646319..c64728eef9 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Program.Bmi2.X64.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/Program.Bmi2.X64.cs @@ -14,6 +14,9 @@ namespace JIT.HardwareIntrinsics.X86 TestList = new Dictionary() { ["ParallelBitDeposit.UInt64"] = ParallelBitDepositUInt64, ["ParallelBitExtract.UInt64"] = ParallelBitExtractUInt64, + ["ZeroHighBits.UInt64"] = ZeroHighBitsUInt64, + ["MultiplyNoFlags.UInt64"] = MultiplyNoFlagsUInt64, + ["MultiplyNoFlags.UInt64.BinRes"] = MultiplyNoFlagsUInt64BinRes, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/ZeroHighBits.UInt64.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/ZeroHighBits.UInt64.cs new file mode 100644 index 0000000000..9315651575 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2.X64/ZeroHighBits.UInt64.cs @@ -0,0 +1,242 @@ +// 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 ZeroHighBitsUInt64() + { + var test = new ScalarBinaryOpTest__ZeroHighBitsUInt64(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__ZeroHighBitsUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public UInt64 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0xFFFFFFFFFFFFFFFF; + testStruct._fld2 = 32; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__ZeroHighBitsUInt64 testClass) + { + var result = Bmi2.X64.ZeroHighBits(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt64 _data1; + private static UInt64 _data2; + + private static UInt64 _clsVar1; + private static UInt64 _clsVar2; + + private UInt64 _fld1; + private UInt64 _fld2; + + static ScalarBinaryOpTest__ZeroHighBitsUInt64() + { + _clsVar1 = 0xFFFFFFFFFFFFFFFF; + _clsVar2 = 32; + } + + public ScalarBinaryOpTest__ZeroHighBitsUInt64() + { + Succeeded = true; + + _fld1 = 0xFFFFFFFFFFFFFFFF; + _fld2 = 32; + + _data1 = 0xFFFFFFFFFFFFFFFF; + _data2 = 32; + } + + public bool IsSupported => Bmi2.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi2.X64.ZeroHighBits( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi2.X64).GetMethod(nameof(Bmi2.X64.ZeroHighBits), new Type[] { typeof(UInt64), typeof(UInt64) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt64)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi2.X64.ZeroHighBits( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi2.X64.ZeroHighBits(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__ZeroHighBitsUInt64(); + var result = Bmi2.X64.ZeroHighBits(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi2.X64.ZeroHighBits(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.X64.ZeroHighBits(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt64 left, UInt64 right, UInt64 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + ulong expectedResult = 0xFFFFFFFF; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2.X64)}.{nameof(Bmi2.X64.ZeroHighBits)}(UInt64, UInt64): ZeroHighBits failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_r.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_r.csproj index 2e2603f1d3..e935361ad6 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_r.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_r.csproj @@ -29,6 +29,9 @@ + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_ro.csproj b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_ro.csproj index 952909b4b0..6f752553ba 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_ro.csproj +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Bmi2_ro.csproj @@ -29,6 +29,9 @@ + + + diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.BinRes.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.BinRes.cs new file mode 100644 index 0000000000..192fe6c788 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.BinRes.cs @@ -0,0 +1,265 @@ +// 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.Reflection; +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 MultiplyNoFlagsUInt32BinRes() + { + var test = new ScalarTernOpBinResTest__MultiplyNoFlagsUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpBinResTest__MultiplyNoFlagsUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public UInt32 _fld2; + public UInt32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt32.MaxValue; + testStruct._fld2 = UInt32.MaxValue; + testStruct._fld3 = 0; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpBinResTest__MultiplyNoFlagsUInt32 testClass) + { + UInt32 buffer = 0; + var result = Bmi2.MultiplyNoFlags(_fld1, _fld2, &buffer); + testClass.ValidateResult(_fld1, _fld2, buffer, result); + } + } + + private static UInt32 _data1; + private static UInt32 _data2; + private static UInt32 _data3; + + private static UInt32 _clsVar1; + private static UInt32 _clsVar2; + private static UInt32 _clsVar3; + + private UInt32 _fld1; + private UInt32 _fld2; + private UInt32 _fld3; + + static ScalarTernOpBinResTest__MultiplyNoFlagsUInt32() + { + _clsVar1 = UInt32.MaxValue; + _clsVar2 = UInt32.MaxValue; + _clsVar3 = 0; + } + + public ScalarTernOpBinResTest__MultiplyNoFlagsUInt32() + { + Succeeded = true; + + _fld1 = UInt32.MaxValue; + _fld2 = UInt32.MaxValue; + _fld3 = 0; + + _data1 = UInt32.MaxValue; + _data2 = UInt32.MaxValue; + _data3 = 0; + } + + public bool IsSupported => Bmi2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + UInt32 buffer = 0; + + var result = Bmi2.MultiplyNoFlags( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + &buffer + ); + + ValidateResult(_data1, _data2, buffer, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + UInt32 buffer = 0; + + var result = typeof(Bmi2).GetMethod(nameof(Bmi2.MultiplyNoFlags), new Type[] { typeof(UInt32), typeof(UInt32), typeof(UInt32*) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)), + Pointer.Box(&buffer, typeof(UInt32*)) + }); + + ValidateResult(_data1, _data2, buffer, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + UInt32 buffer = 0; + var result = Bmi2.MultiplyNoFlags( + _clsVar1, + _clsVar2, + &buffer + ); + + ValidateResult(_clsVar1, _clsVar2, buffer, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var data3 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)); + var result = Bmi2.MultiplyNoFlags(data1, data2, &data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + UInt32 buffer = 0; + + var test = new ScalarTernOpBinResTest__MultiplyNoFlagsUInt32(); + var result = Bmi2.MultiplyNoFlags(test._fld1, test._fld2, &buffer); + + ValidateResult(test._fld1, test._fld2, buffer, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + UInt32 buffer = 0; + + var result = Bmi2.MultiplyNoFlags(_fld1, _fld2, &buffer); + ValidateResult(_fld1, _fld2, buffer, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.MultiplyNoFlags(test._fld1, test._fld2, &test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt32 op1, UInt32 op2, UInt32 lower, UInt32 higher, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + uint expectedHigher = 4294967294, expectedLower = 1; isUnexpectedResult = (expectedHigher != higher) || (expectedLower != lower); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2)}.{nameof(Bmi2.MultiplyNoFlags)}(UInt32, UInt32, UInt32): MultiplyNoFlags failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" lower: {lower}"); + TestLibrary.TestFramework.LogInformation($"higher: {higher}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.cs new file mode 100644 index 0000000000..65b0b73b09 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/MultiplyNoFlags.UInt32.cs @@ -0,0 +1,242 @@ +// 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 MultiplyNoFlagsUInt32() + { + var test = new ScalarBinaryOpTest__MultiplyNoFlagsUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__MultiplyNoFlagsUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public UInt32 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt32.MaxValue; + testStruct._fld2 = UInt32.MaxValue; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__MultiplyNoFlagsUInt32 testClass) + { + var result = Bmi2.MultiplyNoFlags(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt32 _data1; + private static UInt32 _data2; + + private static UInt32 _clsVar1; + private static UInt32 _clsVar2; + + private UInt32 _fld1; + private UInt32 _fld2; + + static ScalarBinaryOpTest__MultiplyNoFlagsUInt32() + { + _clsVar1 = UInt32.MaxValue; + _clsVar2 = UInt32.MaxValue; + } + + public ScalarBinaryOpTest__MultiplyNoFlagsUInt32() + { + Succeeded = true; + + _fld1 = UInt32.MaxValue; + _fld2 = UInt32.MaxValue; + + _data1 = UInt32.MaxValue; + _data2 = UInt32.MaxValue; + } + + public bool IsSupported => Bmi2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi2.MultiplyNoFlags( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi2).GetMethod(nameof(Bmi2.MultiplyNoFlags), new Type[] { typeof(UInt32), typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi2.MultiplyNoFlags( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi2.MultiplyNoFlags(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__MultiplyNoFlagsUInt32(); + var result = Bmi2.MultiplyNoFlags(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi2.MultiplyNoFlags(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.MultiplyNoFlags(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt32 left, UInt32 right, UInt32 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + uint expectedResult = 4294967294; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2)}.{nameof(Bmi2.MultiplyNoFlags)}(UInt32, UInt32): MultiplyNoFlags failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Program.Bmi2.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Program.Bmi2.cs index 31300b1bd9..f8a5d07cca 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Program.Bmi2.cs +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/Program.Bmi2.cs @@ -14,6 +14,9 @@ namespace JIT.HardwareIntrinsics.X86 TestList = new Dictionary() { ["ParallelBitDeposit.UInt32"] = ParallelBitDepositUInt32, ["ParallelBitExtract.UInt32"] = ParallelBitExtractUInt32, + ["ZeroHighBits.UInt32"] = ZeroHighBitsUInt32, + ["MultiplyNoFlags.UInt32"] = MultiplyNoFlagsUInt32, + ["MultiplyNoFlags.UInt32.BinRes"] = MultiplyNoFlagsUInt32BinRes, }; } } diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/ZeroHighBits.UInt32.cs b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/ZeroHighBits.UInt32.cs new file mode 100644 index 0000000000..dc050093d8 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Bmi2/ZeroHighBits.UInt32.cs @@ -0,0 +1,242 @@ +// 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 ZeroHighBitsUInt32() + { + var test = new ScalarBinaryOpTest__ZeroHighBitsUInt32(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarBinaryOpTest__ZeroHighBitsUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public UInt32 _fld2; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 0xFFFFFFFF; + testStruct._fld2 = 16; + + return testStruct; + } + + public void RunStructFldScenario(ScalarBinaryOpTest__ZeroHighBitsUInt32 testClass) + { + var result = Bmi2.ZeroHighBits(_fld1, _fld2); + testClass.ValidateResult(_fld1, _fld2, result); + } + } + + private static UInt32 _data1; + private static UInt32 _data2; + + private static UInt32 _clsVar1; + private static UInt32 _clsVar2; + + private UInt32 _fld1; + private UInt32 _fld2; + + static ScalarBinaryOpTest__ZeroHighBitsUInt32() + { + _clsVar1 = 0xFFFFFFFF; + _clsVar2 = 16; + } + + public ScalarBinaryOpTest__ZeroHighBitsUInt32() + { + Succeeded = true; + + _fld1 = 0xFFFFFFFF; + _fld2 = 16; + + _data1 = 0xFFFFFFFF; + _data2 = 16; + } + + public bool IsSupported => Bmi2.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = Bmi2.ZeroHighBits( + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + ); + + ValidateResult(_data1, _data2, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof(Bmi2).GetMethod(nameof(Bmi2.ZeroHighBits), new Type[] { typeof(UInt32), typeof(UInt32) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)) + }); + + ValidateResult(_data1, _data2, (UInt32)result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = Bmi2.ZeroHighBits( + _clsVar1, + _clsVar2 + ); + + ValidateResult(_clsVar1, _clsVar2, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data1)); + var data2 = Unsafe.ReadUnaligned(ref Unsafe.As(ref _data2)); + var result = Bmi2.ZeroHighBits(data1, data2); + + ValidateResult(data1, data2, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarBinaryOpTest__ZeroHighBitsUInt32(); + var result = Bmi2.ZeroHighBits(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = Bmi2.ZeroHighBits(_fld1, _fld2); + ValidateResult(_fld1, _fld2, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = Bmi2.ZeroHighBits(test._fld1, test._fld2); + + ValidateResult(test._fld1, test._fld2, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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(UInt32 left, UInt32 right, UInt32 result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + uint expectedResult = 0xFFFF; isUnexpectedResult = (expectedResult != result); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(Bmi2)}.{nameof(Bmi2.ZeroHighBits)}(UInt32, UInt32): ZeroHighBits failed:"); + TestLibrary.TestFramework.LogInformation($" left: {left}"); + TestLibrary.TestFramework.LogInformation($" right: {right}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index ea742f90b2..2b5ecfa1f8 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -1020,20 +1020,24 @@ private static readonly (string templateFileName, Dictionary tem private static readonly (string templateFileName, Dictionary templateData)[] Bmi1Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "AndNot", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = ((~left & right) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "ExtractLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = ((unchecked((uint)(-(int)data)) & data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "GetMaskUpToLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) ^ data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "ResetLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) & data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "TrailingZeroCount", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "uint expectedResult = 0; for (int index = 0; ((data >> index) & 1) == 0; index++) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "AndNot", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = ((~left & right) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "ExtractLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = ((unchecked((uint)(-(int)data)) & data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "GetMaskUpToLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) ^ data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "ResetLowestSetBit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) & data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "TrailingZeroCount", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = "uint expectedResult = 0; for (int index = 0; ((data >> index) & 1) == 0; index++) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarTernOpTest.template",new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "BitFieldExtract", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Byte", ["Op3BaseType"] = "Byte", ["NextValueOp1"] = "0x1E000000", ["NextValueOp2"] = "25", ["NextValueOp3"] = "4", ["ValidateResult"] = "uint expectedResult = 15; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1", ["Method"] = "BitFieldExtract", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0x1E000000", ["NextValueOp2"] = "0x0419", ["ValidateResult"] = "uint expectedResult = 15; isUnexpectedResult = (expectedResult != result);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] Bmi1X64Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "AndNot", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = ((~left & right) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "ExtractLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = ((unchecked((ulong)(-(long)data)) & data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "GetMaskUpToLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) ^ data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "ResetLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) & data) != result);" }), - ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "TrailingZeroCount", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "ulong expectedResult = 0; for (int index = 0; ((data >> index) & 1) == 0; index++) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "AndNot", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = ((~left & right) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "ExtractLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = ((unchecked((ulong)(-(long)data)) & data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "GetMaskUpToLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) ^ data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "ResetLowestSetBit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "isUnexpectedResult = (((data - 1) & data) != result);" }), + ("ScalarUnOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "TrailingZeroCount", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = "ulong expectedResult = 0; for (int index = 0; ((data >> index) & 1) == 0; index++) { expectedResult++; } isUnexpectedResult = (expectedResult != result);" }), + ("ScalarTernOpTest.template",new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "BitFieldExtract", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Byte",["Op3BaseType"] = "Byte", ["NextValueOp1"] = "0x1E00000000000000", ["NextValueOp2"] = "57", ["NextValueOp3"] = "4", ["ValidateResult"] = "ulong expectedResult = 15; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi1.X64", ["Method"] = "BitFieldExtract", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt16", ["NextValueOp1"] = "0x1E00000000000000", ["NextValueOp2"] = "0x0439", ["ValidateResult"] = "ulong expectedResult = 15; isUnexpectedResult = (expectedResult != result);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] AesInputs = new [] @@ -1145,14 +1149,20 @@ isUnexpectedResult = (dest != result); private static readonly (string templateFileName, Dictionary templateData)[] Bmi2Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "ParallelBitDeposit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = ValidateBmi2ParallelBitDepositUInt32 }), - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "ParallelBitExtract", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = ValidateBmi2ParallelBitExtractUInt32 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "ParallelBitDeposit", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = ValidateBmi2ParallelBitDepositUInt32 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "ParallelBitExtract", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt32()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt32()", ["ValidateResult"] = ValidateBmi2ParallelBitExtractUInt32 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "ZeroHighBits", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "0xFFFFFFFF", ["NextValueOp2"] = "16", ["ValidateResult"] = "uint expectedResult = 0xFFFF; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "MultiplyNoFlags", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["NextValueOp1"] = "UInt32.MaxValue", ["NextValueOp2"] = "UInt32.MaxValue", ["ValidateResult"] = "uint expectedResult = 4294967294; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarTernOpBinResTest.template", new Dictionary { ["Isa"] = "Bmi2", ["Method"] = "MultiplyNoFlags", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3BaseType"] = "UInt32", ["NextValueOp1"] = "UInt32.MaxValue", ["NextValueOp2"] = "UInt32.MaxValue", ["NextValueOp3"] = "0", ["ValidateResult"] = "uint expectedHigher = 4294967294, expectedLower = 1; isUnexpectedResult = (expectedHigher != higher) || (expectedLower != lower);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] Bmi2X64Inputs = new [] { - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "ParallelBitDeposit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = ValidateBmi2ParallelBitDepositUInt64 }), - ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "ParallelBitExtract", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = ValidateBmi2ParallelBitExtractUInt64 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "ParallelBitDeposit", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = ValidateBmi2ParallelBitDepositUInt64 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "ParallelBitExtract", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "TestLibrary.Generator.GetUInt64()", ["NextValueOp2"] = "TestLibrary.Generator.GetUInt64()", ["ValidateResult"] = ValidateBmi2ParallelBitExtractUInt64 }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "ZeroHighBits", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "0xFFFFFFFFFFFFFFFF", ["NextValueOp2"] = "32", ["ValidateResult"] = "ulong expectedResult = 0xFFFFFFFF; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarBinOpTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "MultiplyNoFlags", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["NextValueOp1"] = "UInt64.MaxValue", ["NextValueOp2"] = "UInt64.MaxValue", ["ValidateResult"] = "ulong expectedResult = 18446744073709551614; isUnexpectedResult = (expectedResult != result);" }), + ("ScalarTernOpBinResTest.template", new Dictionary { ["Isa"] = "Bmi2.X64", ["Method"] = "MultiplyNoFlags", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3BaseType"] = "UInt64", ["NextValueOp1"] = "UInt64.MaxValue", ["NextValueOp2"] = "UInt64.MaxValue", ["NextValueOp3"] = "0", ["ValidateResult"] = "ulong expectedHigher = 18446744073709551614, expectedLower = 1; isUnexpectedResult = (expectedHigher != higher) || (expectedLower != lower);" }), }; private static void ProcessInputs(string groupName, (string templateFileName, Dictionary templateData)[] inputs) @@ -1226,6 +1236,16 @@ private static void ProcessInput(StreamWriter testListFile, string groupName, (s testName += ".Store"; suffix += "Store"; } + else if (input.templateFileName == "ScalarTernOpTest.template") + { + testName += ".3Op"; + suffix += "3Op"; + } + else if (input.templateFileName == "ScalarTernOpBinResTest.template") + { + testName += ".BinRes"; + suffix += "BinRes"; + } if (input.templateFileName == "SimpleUnOpConvTest.template" || input.templateFileName == "SimdScalarUnOpConvTest.template" ) { diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarBinOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarBinOpTest.template index ed05de44a8..04cecabc97 100644 --- a/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarBinOpTest.template +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarBinOpTest.template @@ -158,7 +158,7 @@ namespace JIT.HardwareIntrinsics.X86 TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); var data1 = Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)); - var data2 = Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data2)); + var data2 = Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)); var result = {Isa}.{Method}(data1, data2); ValidateResult(data1, data2, result); diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpBinResTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpBinResTest.template new file mode 100644 index 0000000000..a958777bde --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpBinResTest.template @@ -0,0 +1,265 @@ +// 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.Reflection; +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 {Method}{RetBaseType}BinRes() + { + var test = new ScalarTernOpBinResTest__{Method}{RetBaseType}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpBinResTest__{Method}{RetBaseType} + { + private struct TestStruct + { + public {Op1BaseType} _fld1; + public {Op2BaseType} _fld2; + public {Op3BaseType} _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = {NextValueOp1}; + testStruct._fld2 = {NextValueOp2}; + testStruct._fld3 = {NextValueOp3}; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpBinResTest__{Method}{RetBaseType} testClass) + { + {Op3BaseType} buffer = 0; + var result = {Isa}.{Method}(_fld1, _fld2, &buffer); + testClass.ValidateResult(_fld1, _fld2, buffer, result); + } + } + + private static {Op1BaseType} _data1; + private static {Op2BaseType} _data2; + private static {Op3BaseType} _data3; + + private static {Op1BaseType} _clsVar1; + private static {Op2BaseType} _clsVar2; + private static {Op3BaseType} _clsVar3; + + private {Op1BaseType} _fld1; + private {Op2BaseType} _fld2; + private {Op3BaseType} _fld3; + + static ScalarTernOpBinResTest__{Method}{RetBaseType}() + { + _clsVar1 = {NextValueOp1}; + _clsVar2 = {NextValueOp2}; + _clsVar3 = {NextValueOp3}; + } + + public ScalarTernOpBinResTest__{Method}{RetBaseType}() + { + Succeeded = true; + + _fld1 = {NextValueOp1}; + _fld2 = {NextValueOp2}; + _fld3 = {NextValueOp3}; + + _data1 = {NextValueOp1}; + _data2 = {NextValueOp2}; + _data3 = {NextValueOp3}; + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + {Op3BaseType} buffer = 0; + + var result = {Isa}.{Method}( + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)), + Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)), + &buffer + ); + + ValidateResult(_data1, _data2, buffer, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + {Op3BaseType} buffer = 0; + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1BaseType}), typeof({Op2BaseType}), typeof({Op3BaseType}*) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)), + Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)), + Pointer.Box(&buffer, typeof({Op3BaseType}*)) + }); + + ValidateResult(_data1, _data2, buffer, ({RetBaseType})result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + {Op3BaseType} buffer = 0; + var result = {Isa}.{Method}( + _clsVar1, + _clsVar2, + &buffer + ); + + ValidateResult(_clsVar1, _clsVar2, buffer, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)); + var data2 = Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)); + var data3 = Unsafe.ReadUnaligned<{Op3BaseType}>(ref Unsafe.As<{Op3BaseType}, byte>(ref _data3)); + var result = {Isa}.{Method}(data1, data2, &data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + {Op3BaseType} buffer = 0; + + var test = new ScalarTernOpBinResTest__{Method}{RetBaseType}(); + var result = {Isa}.{Method}(test._fld1, test._fld2, &buffer); + + ValidateResult(test._fld1, test._fld2, buffer, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + {Op3BaseType} buffer = 0; + + var result = {Isa}.{Method}(_fld1, _fld2, &buffer); + ValidateResult(_fld1, _fld2, buffer, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2, &test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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({Op1BaseType} op1, {Op2BaseType} op2, {Op3BaseType} lower, {RetBaseType} higher, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + {ValidateResult} + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1BaseType}, {Op2BaseType}, {Op3BaseType}): {Method} failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" lower: {lower}"); + TestLibrary.TestFramework.LogInformation($"higher: {higher}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTest.template b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTest.template new file mode 100644 index 0000000000..a80a93ee63 --- /dev/null +++ b/tests/src/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTest.template @@ -0,0 +1,255 @@ +// 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 {Method}{RetBaseType}3Op() + { + var test = new ScalarTernOpTest__{Method}{RetBaseType}(); + + if (test.IsSupported) + { + // Validates basic functionality works, using Unsafe.ReadUnaligned + test.RunBasicScenario_UnsafeRead(); + + // Validates calling via reflection works, using Unsafe.ReadUnaligned + test.RunReflectionScenario_UnsafeRead(); + + // Validates passing a static member works + test.RunClsVarScenario(); + + // Validates passing a local works, using Unsafe.ReadUnaligned + test.RunLclVarScenario_UnsafeRead(); + + // Validates passing the field of a local class works + test.RunClassLclFldScenario(); + + // Validates passing an instance member of a class works + test.RunClassFldScenario(); + + // Validates passing the field of a local struct works + test.RunStructLclFldScenario(); + + // Validates passing an instance member of a struct works + test.RunStructFldScenario(); + } + else + { + // Validates we throw on unsupported hardware + test.RunUnsupportedScenario(); + } + + if (!test.Succeeded) + { + throw new Exception("One or more scenarios did not complete as expected."); + } + } + } + + public sealed unsafe class ScalarTernOpTest__{Method}{RetBaseType} + { + private struct TestStruct + { + public {Op1BaseType} _fld1; + public {Op2BaseType} _fld2; + public {Op3BaseType} _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = {NextValueOp1}; + testStruct._fld2 = {NextValueOp2}; + testStruct._fld3 = {NextValueOp3}; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTest__{Method}{RetBaseType} testClass) + { + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static {Op1BaseType} _data1; + private static {Op2BaseType} _data2; + private static {Op3BaseType} _data3; + + private static {Op1BaseType} _clsVar1; + private static {Op2BaseType} _clsVar2; + private static {Op3BaseType} _clsVar3; + + private {Op1BaseType} _fld1; + private {Op2BaseType} _fld2; + private {Op3BaseType} _fld3; + + static ScalarTernOpTest__{Method}{RetBaseType}() + { + _clsVar1 = {NextValueOp1}; + _clsVar2 = {NextValueOp2}; + _clsVar3 = {NextValueOp3}; + } + + public ScalarTernOpTest__{Method}{RetBaseType}() + { + Succeeded = true; + + _fld1 = {NextValueOp1}; + _fld2 = {NextValueOp2}; + _fld3 = {NextValueOp3}; + + _data1 = {NextValueOp1}; + _data2 = {NextValueOp2}; + _data3 = {NextValueOp3}; + } + + public bool IsSupported => {Isa}.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = {Isa}.{Method}( + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)), + Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)), + Unsafe.ReadUnaligned<{Op3BaseType}>(ref Unsafe.As<{Op3BaseType}, byte>(ref _data3)) + ); + + ValidateResult(_data1, _data2, _data3, result); + } + + public void RunReflectionScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunReflectionScenario_UnsafeRead)); + + var result = typeof({Isa}).GetMethod(nameof({Isa}.{Method}), new Type[] { typeof({Op1BaseType}), typeof({Op2BaseType}), typeof({Op3BaseType}) }) + .Invoke(null, new object[] { + Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)), + Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)), + Unsafe.ReadUnaligned<{Op3BaseType}>(ref Unsafe.As<{Op3BaseType}, byte>(ref _data3)) + }); + + ValidateResult(_data1, _data2, _data3, ({RetBaseType})result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = {Isa}.{Method}( + _clsVar1, + _clsVar2, + _clsVar3 + ); + + ValidateResult(_clsVar1, _clsVar2, _clsVar3, result); + } + + public void RunLclVarScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunLclVarScenario_UnsafeRead)); + + var data1 = Unsafe.ReadUnaligned<{Op1BaseType}>(ref Unsafe.As<{Op1BaseType}, byte>(ref _data1)); + var data2 = Unsafe.ReadUnaligned<{Op2BaseType}>(ref Unsafe.As<{Op2BaseType}, byte>(ref _data2)); + var data3 = Unsafe.ReadUnaligned<{Op3BaseType}>(ref Unsafe.As<{Op3BaseType}, byte>(ref _data3)); + var result = {Isa}.{Method}(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTest__{Method}{RetBaseType}(); + var result = {Isa}.{Method}(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = {Isa}.{Method}(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = {Isa}.{Method}(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunStructFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructFldScenario)); + + var test = TestStruct.Create(); + test.RunStructFldScenario(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({Op1BaseType} op1, {Op2BaseType} op2, {Op3BaseType} op3, {RetBaseType} result, [CallerMemberName] string method = "") + { + var isUnexpectedResult = false; + + {ValidateResult} + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<{RetBaseType}>({Op1BaseType}, {Op2BaseType}, {Op3BaseType}): {Method} failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result: {result}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} -- cgit v1.2.3