From 00da1f4f136d115bc671c23f0a4d2bc85eb8d630 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 7 Mar 2022 18:55:30 +0800 Subject: [PATCH 01/71] Add managed api for divrem --- .../X86/X86Base.PlatformNotSupported.cs | 35 +++++++++++++++++++ .../System/Runtime/Intrinsics/X86/X86Base.cs | 35 +++++++++++++++++++ .../ref/System.Runtime.Intrinsics.cs | 7 ++++ 3 files changed, 77 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs index 9ca497a5b8990..8bec6123bb899 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -9,6 +9,7 @@ namespace System.Runtime.Intrinsics.X86 /// /// This class provides access to the x86 base hardware instructions via intrinsics /// + [CLSCompliant(false)] public abstract partial class X86Base { internal X86Base() { } @@ -42,6 +43,18 @@ internal X64() { } /// Its functionality is exposed in the public class. /// internal static ulong BitScanReverse(ulong value) { throw new PlatformNotSupportedException(); } + + /// + /// unsigned __int64 _udiv128(unsigned __int64 highdividend, unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64* remainder) + /// DIV reg/m64 + /// + public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw new PlatformNotSupportedException(); } + + /// + /// __int64 _div128(__int64 highdividend, __int64 lowdividend, __int64 divisor, __int64* remainder) + /// DIV reg/m64 + /// + public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw new PlatformNotSupportedException(); } } /// @@ -77,5 +90,27 @@ internal X64() { } /// PAUSE /// public static void Pause() { throw new PlatformNotSupportedException(); } + + /// + /// unsigned _udiv64(unsigned __int64 dividend, unsigned divisor, unsigned* remainder) + /// DIV reg/m32 + /// + public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw new PlatformNotSupportedException(); } + + /// + /// int _div64(__int64 dividend, int divisor, int* remainder) + /// IDIV reg/m32 + /// + public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw new PlatformNotSupportedException(); } + + /// + /// IDIV reg/m + /// + public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw new PlatformNotSupportedException(); } + + /// + /// IDIV reg/m + /// + public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw new PlatformNotSupportedException(); } } } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs index c8b230b86166b..6a825ac942c97 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -10,6 +10,7 @@ namespace System.Runtime.Intrinsics.X86 /// This class provides access to the x86 base hardware instructions via intrinsics /// [Intrinsic] + [CLSCompliant(false)] public abstract partial class X86Base { internal X86Base() { } @@ -44,6 +45,18 @@ internal X64() { } /// Its functionality is exposed in the public class. /// internal static ulong BitScanReverse(ulong value) => BitScanReverse(value); + + /// + /// unsigned __int64 _udiv128(unsigned __int64 highdividend, unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64* remainder) + /// DIV reg/m64 + /// + public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) => DivRem(lower, upper, divisor); + + /// + /// __int64 _div128(__int64 highdividend, __int64 lowdividend, __int64 divisor, __int64* remainder) + /// DIV reg/m64 + /// + public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) => DivRem(lower, upper, divisor); } /// @@ -84,5 +97,27 @@ public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, /// PAUSE /// public static void Pause() => Pause(); + + /// + /// unsigned _udiv64(unsigned __int64 dividend, unsigned divisor, unsigned* remainder) + /// DIV reg/m32 + /// + public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) => DivRem(lower, upper, divisor); + + /// + /// int _div64(__int64 dividend, int divisor, int* remainder) + /// IDIV reg/m32 + /// + public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) => DivRem(lower, upper, divisor); + + /// + /// IDIV reg/m + /// + public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) => DivRem(lower, upper, divisor); + + /// + /// IDIV reg/m + /// + public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) => DivRem(lower, upper, divisor); } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index ca118e1935384..070245392b053 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4744,16 +4744,23 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } + [System.CLSCompliantAttribute(false)] public abstract partial class X86Base { internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } + public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } + public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } + public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } + public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } public static bool IsSupported { get { throw null; } } + public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } + public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } } } } From d679ccabc21686651f05dc99ecf6a7df5bcec7d9 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 7 Mar 2022 21:44:14 +0800 Subject: [PATCH 02/71] Add NI definition of DivRem --- src/coreclr/jit/hwintrinsiclistxarch.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 7c80de358cf4e..c7e027f77f0ef 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -224,6 +224,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags @@ -232,6 +233,7 @@ HARDWARE_INTRINSIC(X86Base, Pause, // X86Base 64-bit-only Intrinsics HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) +HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags From 4eba5c58a7a552219b7adb912bd25d554e278675 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 04:13:22 +0800 Subject: [PATCH 03/71] Fix DivRem to be static --- .../src/System/Runtime/Intrinsics/X86/X86Base.cs | 12 ++++++------ .../ref/System.Runtime.Intrinsics.cs | 12 ++++++------ 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs index 6a825ac942c97..e07b5979ab463 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -50,13 +50,13 @@ internal X64() { } /// unsigned __int64 _udiv128(unsigned __int64 highdividend, unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64* remainder) /// DIV reg/m64 /// - public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) => DivRem(lower, upper, divisor); + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) => DivRem(lower, upper, divisor); /// /// __int64 _div128(__int64 highdividend, __int64 lowdividend, __int64 divisor, __int64* remainder) /// DIV reg/m64 /// - public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) => DivRem(lower, upper, divisor); + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) => DivRem(lower, upper, divisor); } /// @@ -102,22 +102,22 @@ public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, /// unsigned _udiv64(unsigned __int64 dividend, unsigned divisor, unsigned* remainder) /// DIV reg/m32 /// - public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) => DivRem(lower, upper, divisor); + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) => DivRem(lower, upper, divisor); /// /// int _div64(__int64 dividend, int divisor, int* remainder) /// IDIV reg/m32 /// - public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) => DivRem(lower, upper, divisor); + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) => DivRem(lower, upper, divisor); /// /// IDIV reg/m /// - public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) => DivRem(lower, upper, divisor); + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) => DivRem(lower, upper, divisor); /// /// IDIV reg/m /// - public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) => DivRem(lower, upper, divisor); + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) => DivRem(lower, upper, divisor); } } diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 070245392b053..5b243c3bd602a 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -4750,17 +4750,17 @@ public abstract partial class X86Base internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } - public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } - public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } - public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } - public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } public static bool IsSupported { get { throw null; } } - public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } - public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } } } } From 6f8fbbf07e03e74f4db7fda165d8a801286d54f1 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 07:15:09 +0800 Subject: [PATCH 04/71] Implement DivRem in clrjit --- src/coreclr/jit/compiler.h | 1 + src/coreclr/jit/gentree.h | 2 +- src/coreclr/jit/hwintrinsic.h | 6 +++ src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 33 ++++++++++++ src/coreclr/jit/hwintrinsiclistxarch.h | 4 +- src/coreclr/jit/hwintrinsicxarch.cpp | 57 +++++++++++++++++++-- src/coreclr/jit/lowerxarch.cpp | 14 +++++ src/coreclr/jit/lsraxarch.cpp | 40 ++++++++++++++- src/coreclr/jit/morph.cpp | 4 +- 9 files changed, 151 insertions(+), 10 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index dc8bb8f80cfa4..7f51b174e453a 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4497,6 +4497,7 @@ class Compiler CorInfoType simdBaseJitType, var_types retType, unsigned simdSize); + GenTree* impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index d86d891b30327..8dff4e46a6a9e 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -8146,7 +8146,7 @@ inline var_types GenTree::GetRegTypeByIndex(int regIndex) const #elif defined(TARGET_XARCH) // At this time, the only multi-reg HW intrinsics all return the type of their // arguments. If this changes, we will need a way to record or determine this. - return gtGetOp1()->TypeGet(); + return AsHWIntrinsic()->Op(1)->TypeGet(); #endif } diff --git a/src/coreclr/jit/hwintrinsic.h b/src/coreclr/jit/hwintrinsic.h index 53c392084653e..5495f9fae65a2 100644 --- a/src/coreclr/jit/hwintrinsic.h +++ b/src/coreclr/jit/hwintrinsic.h @@ -744,6 +744,12 @@ struct HWIntrinsicInfo return 2; #endif +#ifdef TARGET_XARCH + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + return 2; +#endif // TARGET_XARCH + default: unreached(); } diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index 094325a4ca4ee..b1d7bc7315b44 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1175,6 +1175,39 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) break; } + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + { + assert(node->GetOperandCount() == 3); + + GenTree* op1 = node->Op(1); + GenTree* op2 = node->Op(2); + GenTree* op3 = node->Op(3); + var_types targetType = op2->TypeGet(); + instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, targetType); + assert(targetType == op3->TypeGet()); + + regNumber op1Reg = op1->GetRegNum(); + regNumber op2Reg = op2->GetRegNum(); + regNumber op3Reg = op3->GetRegNum(); + + emitAttr attr = emitTypeSize(targetType); + emitter* emit = GetEmitter(); + + // op1: EAX, op2: EDX, op3: free + assert(op1Reg != REG_EDX); + assert(op2Reg != REG_EAX); + assert(op3Reg != REG_EDX); + assert(op3Reg != REG_EAX); + emit->emitIns_Mov(INS_mov, attr, REG_EAX, op1Reg, /* canSkip */ true); + emit->emitIns_Mov(INS_mov, attr, REG_EDX, op2Reg, /* canSkip */ true); + + // emit the DIV/IDIV instruction + emit->emitInsBinary(ins, attr, node, op3); + + break; + } + default: unreached(); break; diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index c7e027f77f0ef..8d7780fdb84d8 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -224,7 +224,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags @@ -233,7 +233,7 @@ HARDWARE_INTRINSIC(X86Base, DivRem, // X86Base 64-bit-only Intrinsics HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_BaseTypeFromSecondArg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index aec1be705f3db..c4ff6f119e93f 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -491,8 +491,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { case InstructionSet_Vector256: case InstructionSet_Vector128: - case InstructionSet_X86Base: return impBaseIntrinsic(intrinsic, clsHnd, method, sig, simdBaseJitType, retType, simdSize); + case InstructionSet_X86Base: + return impX86BaseIntrinsic(intrinsic, method, sig); case InstructionSet_SSE: return impSSEIntrinsic(intrinsic, method, sig); case InstructionSet_SSE2: @@ -2194,16 +2195,66 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, break; } + default: + { + return nullptr; + } + } + + return retNode; +} + + +GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) +{ + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + GenTree* op3 = nullptr; + GenTree* op4 = nullptr; + + var_types retType = JITtype2varType(sig->retType); + + switch (intrinsic) + { + case NI_X86Base_Pause: { assert(sig->numArgs == 0); - assert(JITtype2varType(sig->retType) == TYP_VOID); - assert(simdSize == 0); + assert(retType == TYP_VOID); retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; } + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + { + assert(sig->numArgs == 3); + assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); + assert(retType == TYP_STRUCT); + + op3 = impPopStack().val; + op2 = impPopStack().val; + op1 = impPopStack().val; + + GenTreeHWIntrinsic* divRemIntrinsic = gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic); + + const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); + impAssignTempGen(lclNum, divRemIntrinsic, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); + + LclVarDsc* varDsc = lvaGetDesc(lclNum); + // The following is to exclude the fields of the local to have SSA. + varDsc->lvIsMultiRegRet = true; + + GenTreeLclVar* lclVar = gtNewLclvNode(lclNum, varDsc->lvType); + lclVar->SetDoNotCSE(); + lclVar->SetMultiReg(); + + retNode = lclVar; + break; + } + default: { return nullptr; diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 2bf009026bd89..e2b96c7c1c4da 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -6478,6 +6478,20 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) } break; } + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + { + // DIV only allows divisor (op3) in memory + if (TryGetContainableHWIntrinsicOp(node, &op3, &supportsRegOptional)) + { + MakeSrcContained(node, op3); + } + else if (supportsRegOptional) + { + op3->SetRegOptional(); + } + break; + } default: { diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index f9e69773d70cb..fa62dc003b009 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2015,7 +2015,23 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou } int srcCount = 0; - int dstCount = intrinsicTree->IsValue() ? 1 : 0; + int dstCount; + + if (intrinsicTree->IsValue()) + { + if (HWIntrinsicInfo::IsMultiReg(intrinsicId)) + { + dstCount = HWIntrinsicInfo::GetMultiRegCount(intrinsicId); + } + else + { + dstCount = 1; + } + } + else + { + dstCount = 0; + } regMaskTP dstCandidates = RBM_NONE; @@ -2193,6 +2209,25 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou } #endif // TARGET_X86 + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + { + assert(numArgs == 3); + assert(dstCount == 2); + + // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX + srcCount += BuildOperandUses(op1, RBM_EAX); + srcCount += BuildOperandUses(op2, RBM_EDX); + srcCount += BuildOperandUses(op3); + + // result put in EAX and EDX + BuildDef(intrinsicTree, RBM_EAX, 0); + BuildDef(intrinsicTree, RBM_EDX, 1); + + buildUses = false; + break; + } + case NI_BMI2_MultiplyNoFlags: case NI_BMI2_X64_MultiplyNoFlags: { @@ -2463,7 +2498,8 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou } else { - assert(dstCount == 0); + // Currently dstCount = 2 is only used for DivRem, which has special constriants and handled above + assert((dstCount == 0) || (dstCount == 2)); } *pDstCount = dstCount; diff --git a/src/coreclr/jit/morph.cpp b/src/coreclr/jit/morph.cpp index a99d7b9b5bb05..e2cdb4f27c252 100644 --- a/src/coreclr/jit/morph.cpp +++ b/src/coreclr/jit/morph.cpp @@ -10485,7 +10485,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne assert(blockWidth == info.compCompHnd->getClassSize(call->gtRetClsHnd)); #endif } -#ifdef TARGET_ARM64 +#ifdef FEATURE_HW_INTRINSICS else if (effectiveVal->OperIsHWIntrinsic()) { needsIndirection = false; @@ -10495,7 +10495,7 @@ GenTree* Compiler::fgMorphBlockOperand(GenTree* tree, var_types asgType, unsigne assert(HWIntrinsicInfo::IsMultiReg(intrinsic->GetHWIntrinsicId())); #endif } -#endif // TARGET_ARM64 +#endif // FEATURE_HW_INTRINSICS if (lclNode != nullptr) { From 997d8a5ae908ee622ebeb76b242fb3d806ee84b1 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 07:54:53 +0800 Subject: [PATCH 05/71] Add tests for DivRem --- .../X86/Shared/GenerateTests.csx | 21 ++ .../ScalarTernOpTupleBinRetTest.template | 256 ++++++++++++++++++ .../X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base.X64/Program.X86Base.X64.cs | 19 ++ .../X86/X86Base.X64/X86Base.X64_r.csproj | 16 ++ .../X86/X86Base.X64/X86Base.X64_ro.csproj | 16 ++ .../X86/X86Base/DivRem.Int32.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base/DivRem.UInt32.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base/DivRem.nint.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base/DivRem.nuint.Tuple3Op.cs | 256 ++++++++++++++++++ .../X86/X86Base/Program.X86Base.cs | 21 ++ .../X86/X86Base/X86Base_r.csproj | 18 ++ .../X86/X86Base/X86Base_ro.csproj | 18 ++ 14 files changed, 1921 insertions(+) create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 50b7e0b0cdbe2..7fcb91e879bca 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -1261,6 +1261,20 @@ private static readonly (string templateFileName, Dictionary tem ("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 readonly (string templateFileName, Dictionary templateData)[] X86BaseInputs = new [] +{ + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int32", ["Op3BaseType"] = "Int32", ["NextValueOp1"] = "UInt32.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x10001", ["ValidateResult"] = " int expectedQuotient = 0xFFFF; int expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3BaseType"] = "UInt32", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x10001", ["ValidateResult"] = "uint expectedQuotient = 0xFFFF; uint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nint", ["Op3BaseType"] = "nint", ["NextValueOp1"] = "nuint.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-((nint)1 << (IntPtr.Size * 4)) - 1", ["ValidateResult"] = " nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nuint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nuint", ["Op3BaseType"] = "nuint", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "((nuint)1 << (IntPtr.Size * 4)) + 1", ["ValidateResult"] = "nuint expectedQuotient = ((nuint)1 << (IntPtr.Size * 4)) - 1; nuint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), +}; + +private static readonly (string templateFileName, Dictionary templateData)[] X86BaseX64Inputs = new [] +{ + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int64", ["Op3BaseType"] = "Int64", ["NextValueOp1"] = "UInt64.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x100000001", ["ValidateResult"] = " long expectedQuotient = 0xFFFFFFFF; long expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3BaseType"] = "UInt64", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x100000001", ["ValidateResult"] = "ulong expectedQuotient = 0xFFFFFFFF; ulong expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), +}; + private static void ProcessInputs(string groupName, (string templateFileName, Dictionary templateData)[] inputs) { var testListFileName = Path.Combine("..", groupName, $"Program.{groupName}.cs"); @@ -1341,6 +1355,11 @@ private static void ProcessInput(StreamWriter testListFile, string groupName, (s testName += ".BinRes"; suffix += "BinRes"; } + else if (input.templateFileName == "ScalarTernOpTupleBinRetTest.template") + { + testName += ".Tuple3Op"; + suffix += "Tuple3Op"; + } if (input.templateFileName == "SimpleUnOpConvTest.template" || input.templateFileName == "SimdScalarUnOpConvTest.template" ) { @@ -1400,3 +1419,5 @@ ProcessInputs("Bmi2", Bmi2Inputs); ProcessInputs("Bmi2.X64", Bmi2X64Inputs); ProcessInputs("Aes", AesInputs); ProcessInputs("Pclmulqdq", PclmulqdqInputs); +ProcessInputs("X86Base", X86BaseInputs); +ProcessInputs("X86Base.X64", X86BaseX64Inputs); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template b/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template new file mode 100644 index 0000000000000..4f75049a57c64 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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}Tuple3Op() + { + var test = new ScalarTernOpTupleTest__{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 ScalarTernOpTupleTest__{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(ScalarTernOpTupleTest__{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 ScalarTernOpTupleTest__{Method}{RetBaseType}() + { + _clsVar1 = {NextValueOp1}; + _clsVar2 = {NextValueOp2}; + _clsVar3 = {NextValueOp3}; + } + + public ScalarTernOpTupleTest__{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}, {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 ScalarTernOpTupleTest__{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}, {RetBaseType}) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + {ValidateResult} + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof({Isa})}.{nameof({Isa}.{Method})}<({RetBaseType}, {RetBaseType})>({Op1BaseType}, {Op2BaseType}, {Op3BaseType}): {Method} failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs new file mode 100644 index 0000000000000..528b77c934475 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemInt64Tuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemInt64(); + + 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 ScalarTernOpTupleTest__DivRemInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public Int64 _fld2; + public Int64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt64.MaxValue; + testStruct._fld2 = -2; + testStruct._fld3 = -0x100000001; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemInt64 testClass) + { + var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static UInt64 _data1; + private static Int64 _data2; + private static Int64 _data3; + + private static UInt64 _clsVar1; + private static Int64 _clsVar2; + private static Int64 _clsVar3; + + private UInt64 _fld1; + private Int64 _fld2; + private Int64 _fld3; + + static ScalarTernOpTupleTest__DivRemInt64() + { + _clsVar1 = UInt64.MaxValue; + _clsVar2 = -2; + _clsVar3 = -0x100000001; + } + + public ScalarTernOpTupleTest__DivRemInt64() + { + Succeeded = true; + + _fld1 = UInt64.MaxValue; + _fld2 = -2; + _fld3 = -0x100000001; + + _data1 = UInt64.MaxValue; + _data2 = -2; + _data3 = -0x100000001; + } + + public bool IsSupported => X86Base.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.X64.DivRem( + 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(X86Base.X64).GetMethod(nameof(X86Base.X64.DivRem), new Type[] { typeof(UInt64), typeof(Int64), typeof(Int64) }) + .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, ((Int64, Int64))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.X64.DivRem( + _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 = X86Base.X64.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemInt64(); + var result = X86Base.X64.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.X64.DivRem(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, Int64 op2, Int64 op3, (Int64, Int64) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + long expectedQuotient = 0xFFFFFFFF; long expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base.X64)}.{nameof(X86Base.X64.DivRem)}<(Int64, Int64)>(UInt64, Int64, Int64): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs new file mode 100644 index 0000000000000..4704f10cb7809 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemUInt64Tuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemUInt64(); + + 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 ScalarTernOpTupleTest__DivRemUInt64 + { + private struct TestStruct + { + public UInt64 _fld1; + public UInt64 _fld2; + public UInt64 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 1; + testStruct._fld2 = 1; + testStruct._fld3 = 0x100000001; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemUInt64 testClass) + { + var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, 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 ScalarTernOpTupleTest__DivRemUInt64() + { + _clsVar1 = 1; + _clsVar2 = 1; + _clsVar3 = 0x100000001; + } + + public ScalarTernOpTupleTest__DivRemUInt64() + { + Succeeded = true; + + _fld1 = 1; + _fld2 = 1; + _fld3 = 0x100000001; + + _data1 = 1; + _data2 = 1; + _data3 = 0x100000001; + } + + public bool IsSupported => X86Base.X64.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.X64.DivRem( + 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(X86Base.X64).GetMethod(nameof(X86Base.X64.DivRem), 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)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + }); + + ValidateResult(_data1, _data2, _data3, ((UInt64, UInt64))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.X64.DivRem( + _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 = X86Base.X64.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemUInt64(); + var result = X86Base.X64.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.X64.DivRem(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 op3, (UInt64, UInt64) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + ulong expectedQuotient = 0xFFFFFFFF; ulong expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base.X64)}.{nameof(X86Base.X64.DivRem)}<(UInt64, UInt64)>(UInt64, UInt64, UInt64): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs new file mode 100644 index 0000000000000..b8689bb232f71 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -0,0 +1,19 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary() { + ["DivRem.Int64.Tuple3Op"] = DivRemInt64Tuple3Op, + ["DivRem.UInt64.Tuple3Op"] = DivRemUInt64Tuple3Op, + }; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj new file mode 100644 index 0000000000000..d7d05439a4630 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -0,0 +1,16 @@ + + + Exe + true + + + Embedded + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj new file mode 100644 index 0000000000000..36ee17d25d296 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -0,0 +1,16 @@ + + + Exe + true + + + Embedded + True + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs new file mode 100644 index 0000000000000..3667a0c84a23e --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemInt32Tuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemInt32(); + + 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 ScalarTernOpTupleTest__DivRemInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public Int32 _fld2; + public Int32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = UInt32.MaxValue; + testStruct._fld2 = -2; + testStruct._fld3 = -0x10001; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemInt32 testClass) + { + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static UInt32 _data1; + private static Int32 _data2; + private static Int32 _data3; + + private static UInt32 _clsVar1; + private static Int32 _clsVar2; + private static Int32 _clsVar3; + + private UInt32 _fld1; + private Int32 _fld2; + private Int32 _fld3; + + static ScalarTernOpTupleTest__DivRemInt32() + { + _clsVar1 = UInt32.MaxValue; + _clsVar2 = -2; + _clsVar3 = -0x10001; + } + + public ScalarTernOpTupleTest__DivRemInt32() + { + Succeeded = true; + + _fld1 = UInt32.MaxValue; + _fld2 = -2; + _fld3 = -0x10001; + + _data1 = UInt32.MaxValue; + _data2 = -2; + _data3 = -0x10001; + } + + public bool IsSupported => X86Base.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.DivRem( + 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(UInt32), typeof(Int32), typeof(Int32) }) + .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, ((Int32, Int32))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.DivRem( + _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 = X86Base.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemInt32(); + var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.DivRem(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, Int32 op2, Int32 op3, (Int32, Int32) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + int expectedQuotient = 0xFFFF; int expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(Int32, Int32)>(UInt32, Int32, Int32): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs new file mode 100644 index 0000000000000..1ff38fdc921dc --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemUInt32Tuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemUInt32(); + + 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 ScalarTernOpTupleTest__DivRemUInt32 + { + private struct TestStruct + { + public UInt32 _fld1; + public UInt32 _fld2; + public UInt32 _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 1; + testStruct._fld2 = 1; + testStruct._fld3 = 0x10001; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemUInt32 testClass) + { + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, 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 ScalarTernOpTupleTest__DivRemUInt32() + { + _clsVar1 = 1; + _clsVar2 = 1; + _clsVar3 = 0x10001; + } + + public ScalarTernOpTupleTest__DivRemUInt32() + { + Succeeded = true; + + _fld1 = 1; + _fld2 = 1; + _fld3 = 0x10001; + + _data1 = 1; + _data2 = 1; + _data3 = 0x10001; + } + + public bool IsSupported => X86Base.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.DivRem( + 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(X86Base).GetMethod(nameof(X86Base.DivRem), 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)), + Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) + }); + + ValidateResult(_data1, _data2, _data3, ((UInt32, UInt32))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.DivRem( + _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 = X86Base.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemUInt32(); + var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.DivRem(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 op3, (UInt32, UInt32) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + uint expectedQuotient = 0xFFFF; uint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(UInt32, UInt32)>(UInt32, UInt32, UInt32): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs new file mode 100644 index 0000000000000..504de02133008 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemnintTuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemnint(); + + 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 ScalarTernOpTupleTest__DivRemnint + { + private struct TestStruct + { + public nuint _fld1; + public nint _fld2; + public nint _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = nuint.MaxValue; + testStruct._fld2 = -2; + testStruct._fld3 = -((nint)1 << (IntPtr.Size * 4)) - 1; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemnint testClass) + { + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static nuint _data1; + private static nint _data2; + private static nint _data3; + + private static nuint _clsVar1; + private static nint _clsVar2; + private static nint _clsVar3; + + private nuint _fld1; + private nint _fld2; + private nint _fld3; + + static ScalarTernOpTupleTest__DivRemnint() + { + _clsVar1 = nuint.MaxValue; + _clsVar2 = -2; + _clsVar3 = -((nint)1 << (IntPtr.Size * 4)) - 1; + } + + public ScalarTernOpTupleTest__DivRemnint() + { + Succeeded = true; + + _fld1 = nuint.MaxValue; + _fld2 = -2; + _fld3 = -((nint)1 << (IntPtr.Size * 4)) - 1; + + _data1 = nuint.MaxValue; + _data2 = -2; + _data3 = -((nint)1 << (IntPtr.Size * 4)) - 1; + } + + public bool IsSupported => X86Base.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.DivRem( + 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(nuint), typeof(nint), typeof(nint) }) + .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, ((nint, nint))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.DivRem( + _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 = X86Base.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemnint(); + var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.DivRem(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(nuint op1, nint op2, nint op3, (nint, nint) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(nint, nint)>(nuint, nint, nint): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs new file mode 100644 index 0000000000000..9644c16222b5c --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs @@ -0,0 +1,256 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +/****************************************************************************** + * 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 DivRemnuintTuple3Op() + { + var test = new ScalarTernOpTupleTest__DivRemnuint(); + + 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 ScalarTernOpTupleTest__DivRemnuint + { + private struct TestStruct + { + public nuint _fld1; + public nuint _fld2; + public nuint _fld3; + + public static TestStruct Create() + { + var testStruct = new TestStruct(); + + testStruct._fld1 = 1; + testStruct._fld2 = 1; + testStruct._fld3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + + return testStruct; + } + + public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemnuint testClass) + { + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + testClass.ValidateResult(_fld1, _fld2, _fld3, result); + } + } + + private static nuint _data1; + private static nuint _data2; + private static nuint _data3; + + private static nuint _clsVar1; + private static nuint _clsVar2; + private static nuint _clsVar3; + + private nuint _fld1; + private nuint _fld2; + private nuint _fld3; + + static ScalarTernOpTupleTest__DivRemnuint() + { + _clsVar1 = 1; + _clsVar2 = 1; + _clsVar3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + } + + public ScalarTernOpTupleTest__DivRemnuint() + { + Succeeded = true; + + _fld1 = 1; + _fld2 = 1; + _fld3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + + _data1 = 1; + _data2 = 1; + _data3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + } + + public bool IsSupported => X86Base.IsSupported; + + public bool Succeeded { get; set; } + + public void RunBasicScenario_UnsafeRead() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); + + var result = X86Base.DivRem( + 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(nuint), typeof(nuint), typeof(nuint) }) + .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, ((nuint, nuint))result); + } + + public void RunClsVarScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); + + var result = X86Base.DivRem( + _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 = X86Base.DivRem(data1, data2, data3); + + ValidateResult(data1, data2, data3, result); + } + + public void RunClassLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); + + var test = new ScalarTernOpTupleTest__DivRemnuint(); + var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); + + ValidateResult(test._fld1, test._fld2, test._fld3, result); + } + + public void RunClassFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); + + var result = X86Base.DivRem(_fld1, _fld2, _fld3); + ValidateResult(_fld1, _fld2, _fld3, result); + } + + public void RunStructLclFldScenario() + { + TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); + + var test = TestStruct.Create(); + var result = X86Base.DivRem(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(nuint op1, nuint op2, nuint op3, (nuint, nuint) result, [CallerMemberName] string method = "") + { + (var ret1, var ret2) = result; + var isUnexpectedResult = false; + + nuint expectedQuotient = ((nuint)1 << (IntPtr.Size * 4)) - 1; nuint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + + if (isUnexpectedResult) + { + TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(nuint, nuint)>(nuint, nuint, nuint): DivRem failed:"); + TestLibrary.TestFramework.LogInformation($" op1: {op1}"); + TestLibrary.TestFramework.LogInformation($" op2: {op2}"); + TestLibrary.TestFramework.LogInformation($" op3: {op3}"); + TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); + TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); + TestLibrary.TestFramework.LogInformation(string.Empty); + + Succeeded = false; + } + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs new file mode 100644 index 0000000000000..5f5273de801c5 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -0,0 +1,21 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +using System; +using System.Collections.Generic; + +namespace JIT.HardwareIntrinsics.X86 +{ + public static partial class Program + { + static Program() + { + TestList = new Dictionary() { + ["DivRem.Int32.Tuple3Op"] = DivRemInt32Tuple3Op, + ["DivRem.UInt32.Tuple3Op"] = DivRemUInt32Tuple3Op, + ["DivRem.nint.Tuple3Op"] = DivRemnintTuple3Op, + ["DivRem.nuint.Tuple3Op"] = DivRemnuintTuple3Op, + }; + } + } +} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj new file mode 100644 index 0000000000000..7010a8f041733 --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -0,0 +1,18 @@ + + + Exe + true + + + Embedded + + + + + + + + + + + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj new file mode 100644 index 0000000000000..51030e1812d5a --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -0,0 +1,18 @@ + + + Exe + true + + + Embedded + True + + + + + + + + + + From c0c3dd6d2b007c6061fa351987532dbdadbff42d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 10:42:07 +0800 Subject: [PATCH 06/71] Adjust lsra and RMW --- src/coreclr/jit/gentree.cpp | 2 ++ src/coreclr/jit/lsraxarch.cpp | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 8350e7ad725fb..f3a3c65d7a7c0 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17956,6 +17956,8 @@ bool GenTree::isRMWHWIntrinsic(Compiler* comp) case NI_FMA_MultiplySubtractNegated: case NI_FMA_MultiplySubtractNegatedScalar: case NI_FMA_MultiplySubtractScalar: + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: { return true; } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index fa62dc003b009..272ab3ac69be9 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2214,11 +2214,12 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { assert(numArgs == 3); assert(dstCount == 2); + assert(isRMW); // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); srcCount += BuildOperandUses(op2, RBM_EDX); - srcCount += BuildOperandUses(op3); + srcCount += BuildDelayFreeUses(op3, op1, allRegs(TYP_INT) & ~(RBM_RAX | RBM_RDX)); // result put in EAX and EDX BuildDef(intrinsicTree, RBM_EAX, 0); From c08cee7640a21de1f4e1b64593c0691c613511d4 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 22:44:34 +0800 Subject: [PATCH 07/71] Use DivRem intrinsic in Math --- .../System.Private.CoreLib/src/System/Math.cs | 122 ++++++++++++++---- 1 file changed, 95 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 52f95fa347057..a93f9bc25ca8a 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -317,6 +317,12 @@ public static int DivRem(int a, int b, out int result) // Restore to using % and / when the JIT is able to eliminate one of the idivs. // In the meantime, a * and - is measurably faster than an extra /. + if (X86Base.IsSupported) + { + (int quitient, result) = X86Base.DivRem((uint)a, a >> 31, b); + return quitient; + } + int div = a / b; result = a - (div * b); return div; @@ -324,6 +330,12 @@ public static int DivRem(int a, int b, out int result) public static long DivRem(long a, long b, out long result) { + if (X86Base.X64.IsSupported) + { + (long quitient, result) = X86Base.X64.DivRem((ulong)a, a >> 63, b); + return quitient; + } + long div = a / b; result = a - (div * b); return div; @@ -338,6 +350,13 @@ public static long DivRem(long a, long b, out long result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { + if (X86Base.IsSupported) + { + int dividend = left; + (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); + return ((sbyte)quitient, (sbyte)remainder); + } + sbyte quotient = (sbyte)(left / right); return (quotient, (sbyte)(left - (quotient * right))); } @@ -350,6 +369,12 @@ public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { + if (X86Base.IsSupported) + { + (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); + return ((byte)quitient, (byte)remainder); + } + byte quotient = (byte)(left / right); return (quotient, (byte)(left - (quotient * right))); } @@ -362,6 +387,13 @@ public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (short Quotient, short Remainder) DivRem(short left, short right) { + if (X86Base.IsSupported) + { + int dividend = left; + (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); + return ((short)quitient, (short)remainder); + } + short quotient = (short)(left / right); return (quotient, (short)(left - (quotient * right))); } @@ -375,6 +407,12 @@ public static (short Quotient, short Remainder) DivRem(short left, short right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { + if (X86Base.IsSupported) + { + (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); + return ((ushort)quitient, (ushort)remainder); + } + ushort quotient = (ushort)(left / right); return (quotient, (ushort)(left - (quotient * right))); } @@ -387,6 +425,11 @@ public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort rig [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (int Quotient, int Remainder) DivRem(int left, int right) { + if (X86Base.IsSupported) + { + return X86Base.DivRem((uint)left, left >> 31, right); + } + int quotient = left / right; return (quotient, left - (quotient * right)); } @@ -400,6 +443,11 @@ public static (int Quotient, int Remainder) DivRem(int left, int right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { + if (X86Base.IsSupported) + { + return X86Base.DivRem(left, 0u, right); + } + uint quotient = left / right; return (quotient, left - (quotient * right)); } @@ -412,6 +460,11 @@ public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (long Quotient, long Remainder) DivRem(long left, long right) { + if (X86Base.X64.IsSupported) + { + return X86Base.X64.DivRem((ulong)left, left >> 63, right); + } + long quotient = left / right; return (quotient, left - (quotient * right)); } @@ -425,6 +478,11 @@ public static (long Quotient, long Remainder) DivRem(long left, long right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { + if (X86Base.X64.IsSupported) + { + return X86Base.X64.DivRem(left, 0ul, right); + } + ulong quotient = left / right; return (quotient, left - (quotient * right)); } @@ -437,6 +495,11 @@ public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { + if (X86Base.IsSupported) + { + return X86Base.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); + } + nint quotient = left / right; return (quotient, left - (quotient * right)); } @@ -450,6 +513,11 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { + if (X86Base.IsSupported) + { + return X86Base.DivRem(left, (nuint)0, right); + } + nuint quotient = left / right; return (quotient, left - (quotient * right)); } @@ -1341,45 +1409,45 @@ public static unsafe double Round(double value, int digits, MidpointRounding mod // Rounds to the nearest value; if the number falls midway, // it is rounded to the nearest value with an even least significant digit case MidpointRounding.ToEven: - { - value = Round(value); - break; - } + { + value = Round(value); + break; + } // Rounds to the nearest value; if the number falls midway, // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) case MidpointRounding.AwayFromZero: - { - double fraction = ModF(value, &value); - - if (Abs(fraction) >= 0.5) { - value += Sign(fraction); - } + double fraction = ModF(value, &value); - break; - } + if (Abs(fraction) >= 0.5) + { + value += Sign(fraction); + } + + break; + } // Directed rounding: Round to the nearest value, toward to zero case MidpointRounding.ToZero: - { - value = Truncate(value); - break; - } + { + value = Truncate(value); + break; + } // Directed Rounding: Round down to the next value, toward negative infinity case MidpointRounding.ToNegativeInfinity: - { - value = Floor(value); - break; - } + { + value = Floor(value); + break; + } // Directed rounding: Round up to the next value, toward positive infinity case MidpointRounding.ToPositiveInfinity: - { - value = Ceiling(value); - break; - } + { + value = Ceiling(value); + break; + } default: - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); - } + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); + } } value /= power10; From 1804350b186f0ec7e8e718743291d1370bc3b73d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sat, 12 Mar 2022 22:45:48 +0800 Subject: [PATCH 08/71] Bring lower change from coreclr#37928 This fixes error while crossgen2 compiling Utf8Formatter.TryFormat(TimeSpan). --- src/coreclr/jit/lower.cpp | 8 ++++---- src/coreclr/jit/lowerxarch.cpp | 10 ++++++++++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index eaac88aa6df4f..3e97e12c34976 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6749,7 +6749,7 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc) { bool canEnregister = false; -#if FEATURE_MULTIREG_RET +#if FEATURE_MULTIREG_RET || FEATURE_HW_INTRINSICS LclVarDsc* varDsc = comp->lvaGetDesc(lclNode->GetLclNum()); if ((comp->lvaEnregMultiRegVars) && varDsc->lvPromoted) { @@ -6776,10 +6776,10 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* } } #ifdef TARGET_XARCH - // For local stores on XARCH we only handle mismatched src/dest register count for - // calls of SIMD type. If the source was another lclVar similarly promoted, we would + // For local stores on XARCH we can't handle another lclVar source. + // If the source was another lclVar similarly promoted, we would // have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && !lclNode->gtGetOp1()->OperIs(GT_CALL)) + if (lclNode->OperIs(GT_STORE_LCL_VAR) && lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) { canEnregister = false; } diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index e2b96c7c1c4da..e7e9bff1899ae 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -384,6 +384,16 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) ContainBlockStoreAddress(blkNode, size, dstAddr); } + else if (src->OperIsHWIntrinsic()) + { + assert(!blkNode->AsObj()->GetLayout()->HasGCPtr()); + if (blkNode->OperIs(GT_STORE_OBJ)) + { + blkNode->SetOper(GT_STORE_BLK); + } + blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; + ContainBlockStoreAddress(blkNode, size, dstAddr); + } else { assert(blkNode->OperIs(GT_STORE_BLK, GT_STORE_DYN_BLK)); From 46c3f7848c2765b3766dd2f89e211ad0a10e7ff7 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 13:31:00 +0800 Subject: [PATCH 09/71] Fix signedness of DIV --- src/coreclr/jit/compiler.h | 5 ++++- src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 4 ++-- src/coreclr/jit/hwintrinsiclistxarch.h | 4 ++-- src/coreclr/jit/hwintrinsicxarch.cpp | 21 +++++++++++-------- .../X86/Shared/GenerateTests.csx | 12 +++++------ .../X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs | 10 ++++----- .../X86/X86Base.X64/X86Base.X64_r.csproj | 2 +- .../X86/X86Base.X64/X86Base.X64_ro.csproj | 2 +- .../X86/X86Base/DivRem.UInt32.Tuple3Op.cs | 10 ++++----- .../X86/X86Base/DivRem.nint.Tuple3Op.cs | 2 +- .../X86/X86Base/DivRem.nuint.Tuple3Op.cs | 10 ++++----- 11 files changed, 44 insertions(+), 38 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 7f51b174e453a..e4f71377d0114 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -4497,7 +4497,10 @@ class Compiler CorInfoType simdBaseJitType, var_types retType, unsigned simdSize); - GenTree* impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); + GenTree* impX86BaseIntrinsic(NamedIntrinsic intrinsic, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + CorInfoType simdBaseJitType); GenTree* impSSEIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impSSE2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); GenTree* impAvxOrAvx2Intrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig); diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index b1d7bc7315b44..4a7e0474afb29 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1180,12 +1180,12 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) { assert(node->GetOperandCount() == 3); + // SIMD base type is from signature and can distinguish signed and unsigned + var_types targetType = node->GetSimdBaseType(); GenTree* op1 = node->Op(1); GenTree* op2 = node->Op(2); GenTree* op3 = node->Op(3); - var_types targetType = op2->TypeGet(); instruction ins = HWIntrinsicInfo::lookupIns(intrinsicId, targetType); - assert(targetType == op3->TypeGet()); regNumber op1Reg = op1->GetRegNum(); regNumber op2Reg = op2->GetRegNum(); diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 8d7780fdb84d8..4e88584f7c37d 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -224,7 +224,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags @@ -233,7 +233,7 @@ HARDWARE_INTRINSIC(X86Base, DivRem, // X86Base 64-bit-only Intrinsics HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index c4ff6f119e93f..317d92ba4244e 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -493,7 +493,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case InstructionSet_Vector128: return impBaseIntrinsic(intrinsic, clsHnd, method, sig, simdBaseJitType, retType, simdSize); case InstructionSet_X86Base: - return impX86BaseIntrinsic(intrinsic, method, sig); + return impX86BaseIntrinsic(intrinsic, method, sig, simdBaseJitType); case InstructionSet_SSE: return impSSEIntrinsic(intrinsic, method, sig); case InstructionSet_SSE2: @@ -551,13 +551,8 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, return nullptr; } - var_types simdBaseType = TYP_UNKNOWN; - - if (intrinsic != NI_X86Base_Pause) - { - simdBaseType = JitType2PreciseVarType(simdBaseJitType); - assert(varTypeIsArithmetic(simdBaseType)); - } + var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + assert(varTypeIsArithmetic(simdBaseType)); switch (intrinsic) { @@ -2205,7 +2200,10 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, } -GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig) +GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + CorInfoType simdBaseJitType) { GenTree* retNode = nullptr; GenTree* op1 = nullptr; @@ -2222,6 +2220,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_ { assert(sig->numArgs == 0); assert(retType == TYP_VOID); + assert(simdBaseJitType == CORINFO_TYPE_UNDEF); retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; @@ -2233,6 +2232,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_ assert(sig->numArgs == 3); assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); assert(retType == TYP_STRUCT); + assert(simdBaseJitType != CORINFO_TYPE_UNDEF); op3 = impPopStack().val; op2 = impPopStack().val; @@ -2240,6 +2240,9 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_ GenTreeHWIntrinsic* divRemIntrinsic = gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic); + // Store the type from signature into SIMD base type for convenience + divRemIntrinsic->SetSimdBaseJitType(simdBaseJitType); + const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); impAssignTempGen(lclNum, divRemIntrinsic, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx b/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx index 7fcb91e879bca..d60a912965a54 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx +++ b/src/tests/JIT/HardwareIntrinsics/X86/Shared/GenerateTests.csx @@ -1263,16 +1263,16 @@ private static readonly (string templateFileName, Dictionary tem private static readonly (string templateFileName, Dictionary templateData)[] X86BaseInputs = new [] { - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int32", ["Op3BaseType"] = "Int32", ["NextValueOp1"] = "UInt32.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x10001", ["ValidateResult"] = " int expectedQuotient = 0xFFFF; int expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3BaseType"] = "UInt32", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x10001", ["ValidateResult"] = "uint expectedQuotient = 0xFFFF; uint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nint", ["Op3BaseType"] = "nint", ["NextValueOp1"] = "nuint.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-((nint)1 << (IntPtr.Size * 4)) - 1", ["ValidateResult"] = " nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nuint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nuint", ["Op3BaseType"] = "nuint", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "((nuint)1 << (IntPtr.Size * 4)) + 1", ["ValidateResult"] = "nuint expectedQuotient = ((nuint)1 << (IntPtr.Size * 4)) - 1; nuint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "Int32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "Int32", ["Op3BaseType"] = "Int32", ["NextValueOp1"] = "UInt32.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x10001", ["ValidateResult"] = " int expectedQuotient = 0xFFFF; int expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "UInt32", ["Op1BaseType"] = "UInt32", ["Op2BaseType"] = "UInt32", ["Op3BaseType"] = "UInt32", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x80000000", ["ValidateResult"] = "uint expectedQuotient = 2; uint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nint", ["Op3BaseType"] = "nint", ["NextValueOp1"] = "nuint.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-((nint)1 << (IntPtr.Size * 4)) - 1", ["ValidateResult"] = " nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base", ["Method"] = "DivRem", ["RetBaseType"] = "nuint", ["Op1BaseType"] = "nuint", ["Op2BaseType"] = "nuint", ["Op3BaseType"] = "nuint", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "(nuint)nint.MinValue", ["ValidateResult"] = "nuint expectedQuotient = 2; nuint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), }; private static readonly (string templateFileName, Dictionary templateData)[] X86BaseX64Inputs = new [] { - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int64", ["Op3BaseType"] = "Int64", ["NextValueOp1"] = "UInt64.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x100000001", ["ValidateResult"] = " long expectedQuotient = 0xFFFFFFFF; long expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), - ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3BaseType"] = "UInt64", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x100000001", ["ValidateResult"] = "ulong expectedQuotient = 0xFFFFFFFF; ulong expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "Int64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "Int64", ["Op3BaseType"] = "Int64", ["NextValueOp1"] = "UInt64.MaxValue", ["NextValueOp2"] = "-2", ["NextValueOp3"] = "-0x100000001", ["ValidateResult"] = " long expectedQuotient = 0xFFFFFFFF; long expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), + ("ScalarTernOpTupleBinRetTest.template", new Dictionary { ["Isa"] = "X86Base.X64", ["Method"] = "DivRem", ["RetBaseType"] = "UInt64", ["Op1BaseType"] = "UInt64", ["Op2BaseType"] = "UInt64", ["Op3BaseType"] = "UInt64", ["NextValueOp1"] = "1", ["NextValueOp2"] = "1", ["NextValueOp3"] = "0x8000000000000000", ["ValidateResult"] = "ulong expectedQuotient = 2; ulong expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2);" }), }; private static void ProcessInputs(string groupName, (string templateFileName, Dictionary templateData)[] inputs) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs index 4704f10cb7809..186632f1654b0 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs @@ -75,7 +75,7 @@ public static TestStruct Create() testStruct._fld1 = 1; testStruct._fld2 = 1; - testStruct._fld3 = 0x100000001; + testStruct._fld3 = 0x8000000000000000; return testStruct; } @@ -103,7 +103,7 @@ static ScalarTernOpTupleTest__DivRemUInt64() { _clsVar1 = 1; _clsVar2 = 1; - _clsVar3 = 0x100000001; + _clsVar3 = 0x8000000000000000; } public ScalarTernOpTupleTest__DivRemUInt64() @@ -112,11 +112,11 @@ public ScalarTernOpTupleTest__DivRemUInt64() _fld1 = 1; _fld2 = 1; - _fld3 = 0x100000001; + _fld3 = 0x8000000000000000; _data1 = 1; _data2 = 1; - _data3 = 0x100000001; + _data3 = 0x8000000000000000; } public bool IsSupported => X86Base.X64.IsSupported; @@ -237,7 +237,7 @@ private void ValidateResult(UInt64 op1, UInt64 op2, UInt64 op3, (UInt64, UInt64) (var ret1, var ret2) = result; var isUnexpectedResult = false; - ulong expectedQuotient = 0xFFFFFFFF; ulong expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + ulong expectedQuotient = 2; ulong expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); if (isUnexpectedResult) { diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index d7d05439a4630..4fca0c12394a8 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index 36ee17d25d296..8e189c9d253a4 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -10,7 +10,7 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs index 1ff38fdc921dc..e94ff31851325 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs @@ -75,7 +75,7 @@ public static TestStruct Create() testStruct._fld1 = 1; testStruct._fld2 = 1; - testStruct._fld3 = 0x10001; + testStruct._fld3 = 0x80000000; return testStruct; } @@ -103,7 +103,7 @@ static ScalarTernOpTupleTest__DivRemUInt32() { _clsVar1 = 1; _clsVar2 = 1; - _clsVar3 = 0x10001; + _clsVar3 = 0x80000000; } public ScalarTernOpTupleTest__DivRemUInt32() @@ -112,11 +112,11 @@ public ScalarTernOpTupleTest__DivRemUInt32() _fld1 = 1; _fld2 = 1; - _fld3 = 0x10001; + _fld3 = 0x80000000; _data1 = 1; _data2 = 1; - _data3 = 0x10001; + _data3 = 0x80000000; } public bool IsSupported => X86Base.IsSupported; @@ -237,7 +237,7 @@ private void ValidateResult(UInt32 op1, UInt32 op2, UInt32 op3, (UInt32, UInt32) (var ret1, var ret2) = result; var isUnexpectedResult = false; - uint expectedQuotient = 0xFFFF; uint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + uint expectedQuotient = 2; uint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); if (isUnexpectedResult) { diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs index 504de02133008..93ea93ca70fcf 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs @@ -237,7 +237,7 @@ private void ValidateResult(nuint op1, nint op2, nint op3, (nint, nint) result, (var ret1, var ret2) = result; var isUnexpectedResult = false; - nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); if (isUnexpectedResult) { diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs index 9644c16222b5c..941bb943f9e75 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs @@ -75,7 +75,7 @@ public static TestStruct Create() testStruct._fld1 = 1; testStruct._fld2 = 1; - testStruct._fld3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + testStruct._fld3 = (nuint)nint.MinValue; return testStruct; } @@ -103,7 +103,7 @@ static ScalarTernOpTupleTest__DivRemnuint() { _clsVar1 = 1; _clsVar2 = 1; - _clsVar3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + _clsVar3 = (nuint)nint.MinValue; } public ScalarTernOpTupleTest__DivRemnuint() @@ -112,11 +112,11 @@ public ScalarTernOpTupleTest__DivRemnuint() _fld1 = 1; _fld2 = 1; - _fld3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + _fld3 = (nuint)nint.MinValue; _data1 = 1; _data2 = 1; - _data3 = ((nuint)1 << (IntPtr.Size * 4)) + 1; + _data3 = (nuint)nint.MinValue; } public bool IsSupported => X86Base.IsSupported; @@ -237,7 +237,7 @@ private void ValidateResult(nuint op1, nuint op2, nuint op3, (nuint, nuint) resu (var ret1, var ret2) = result; var isUnexpectedResult = false; - nuint expectedQuotient = ((nuint)1 << (IntPtr.Size * 4)) - 1; nuint expectedReminder = 2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); + nuint expectedQuotient = 2; nuint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); if (isUnexpectedResult) { From 2dbd2e924aaa4ff065962a6708b67bd333b19e3c Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 13:52:37 +0800 Subject: [PATCH 10/71] Revert RMW change and fix reg allocation --- src/coreclr/jit/gentree.cpp | 2 -- src/coreclr/jit/hwintrinsiclistxarch.h | 4 ++-- src/coreclr/jit/lsraxarch.cpp | 4 ++-- 3 files changed, 4 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index f3a3c65d7a7c0..8350e7ad725fb 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17956,8 +17956,6 @@ bool GenTree::isRMWHWIntrinsic(Compiler* comp) case NI_FMA_MultiplySubtractNegated: case NI_FMA_MultiplySubtractNegatedScalar: case NI_FMA_MultiplySubtractScalar: - case NI_X86Base_DivRem: - case NI_X86Base_X64_DivRem: { return true; } diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 4e88584f7c37d..475ad7f34a5a7 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -224,7 +224,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags @@ -233,7 +233,7 @@ HARDWARE_INTRINSIC(X86Base, DivRem, // X86Base 64-bit-only Intrinsics HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 272ab3ac69be9..38757f0af6367 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2214,12 +2214,12 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { assert(numArgs == 3); assert(dstCount == 2); - assert(isRMW); + assert(!isRMW); // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); srcCount += BuildOperandUses(op2, RBM_EDX); - srcCount += BuildDelayFreeUses(op3, op1, allRegs(TYP_INT) & ~(RBM_RAX | RBM_RDX)); + srcCount += BuildOperandUses(op3); // result put in EAX and EDX BuildDef(intrinsicTree, RBM_EAX, 0); From 1b6d09b322fa023d46cb2fd4a0bd1f259f830d1f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 14:07:41 +0800 Subject: [PATCH 11/71] Fix import of X64 intrinsic --- src/coreclr/jit/hwintrinsicxarch.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 317d92ba4244e..e418cd1ceb158 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -493,6 +493,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case InstructionSet_Vector128: return impBaseIntrinsic(intrinsic, clsHnd, method, sig, simdBaseJitType, retType, simdSize); case InstructionSet_X86Base: + case InstructionSet_X86Base_X64: return impX86BaseIntrinsic(intrinsic, method, sig, simdBaseJitType); case InstructionSet_SSE: return impSSEIntrinsic(intrinsic, method, sig); From 3ef360002b38b570528e14640abdf7359a27371f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 18:16:27 +0800 Subject: [PATCH 12/71] Fix static in PNSE version --- .../Intrinsics/X86/X86Base.PlatformNotSupported.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs index 8bec6123bb899..7cfbfeda6ebac 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -48,13 +48,13 @@ internal X64() { } /// unsigned __int64 _udiv128(unsigned __int64 highdividend, unsigned __int64 lowdividend, unsigned __int64 divisor, unsigned __int64* remainder) /// DIV reg/m64 /// - public (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw new PlatformNotSupportedException(); } + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw new PlatformNotSupportedException(); } /// /// __int64 _div128(__int64 highdividend, __int64 lowdividend, __int64 divisor, __int64* remainder) /// DIV reg/m64 /// - public (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw new PlatformNotSupportedException(); } + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw new PlatformNotSupportedException(); } } /// @@ -95,22 +95,22 @@ internal X64() { } /// unsigned _udiv64(unsigned __int64 dividend, unsigned divisor, unsigned* remainder) /// DIV reg/m32 /// - public (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw new PlatformNotSupportedException(); } + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw new PlatformNotSupportedException(); } /// /// int _div64(__int64 dividend, int divisor, int* remainder) /// IDIV reg/m32 /// - public (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw new PlatformNotSupportedException(); } + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw new PlatformNotSupportedException(); } /// /// IDIV reg/m /// - public (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw new PlatformNotSupportedException(); } + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw new PlatformNotSupportedException(); } /// /// IDIV reg/m /// - public (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw new PlatformNotSupportedException(); } + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw new PlatformNotSupportedException(); } } } From acaf2112c70cade5ff9e10d5c0c7243e930da928 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 18:18:41 +0800 Subject: [PATCH 13/71] Fix accidential indent change --- .../System.Private.CoreLib/src/System/Math.cs | 54 +++++++++---------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index a93f9bc25ca8a..0e1218682018e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -1409,45 +1409,45 @@ public static unsafe double Round(double value, int digits, MidpointRounding mod // Rounds to the nearest value; if the number falls midway, // it is rounded to the nearest value with an even least significant digit case MidpointRounding.ToEven: - { - value = Round(value); - break; - } + { + value = Round(value); + break; + } // Rounds to the nearest value; if the number falls midway, // it is rounded to the nearest value above (for positive numbers) or below (for negative numbers) case MidpointRounding.AwayFromZero: - { - double fraction = ModF(value, &value); - - if (Abs(fraction) >= 0.5) - { - value += Sign(fraction); - } + { + double fraction = ModF(value, &value); - break; + if (Abs(fraction) >= 0.5) + { + value += Sign(fraction); } + + break; + } // Directed rounding: Round to the nearest value, toward to zero case MidpointRounding.ToZero: - { - value = Truncate(value); - break; - } + { + value = Truncate(value); + break; + } // Directed Rounding: Round down to the next value, toward negative infinity case MidpointRounding.ToNegativeInfinity: - { - value = Floor(value); - break; - } + { + value = Floor(value); + break; + } // Directed rounding: Round up to the next value, toward positive infinity case MidpointRounding.ToPositiveInfinity: - { - value = Ceiling(value); - break; - } + { + value = Ceiling(value); + break; + } default: - { - throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); - } + { + throw new ArgumentException(SR.Format(SR.Argument_InvalidEnumValue, mode, nameof(MidpointRounding)), nameof(mode)); + } } value /= power10; From 728440d429f9ecc3b9ac55fc92c4c5658a7d90d1 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 21:38:30 +0800 Subject: [PATCH 14/71] Apply format patch --- src/coreclr/jit/hwintrinsicxarch.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index e418cd1ceb158..d68a5a724b97b 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2200,7 +2200,6 @@ GenTree* Compiler::impBaseIntrinsic(NamedIntrinsic intrinsic, return retNode; } - GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, CORINFO_METHOD_HANDLE method, CORINFO_SIG_INFO* sig, From 4eace5de1cb234ad2402e7d86ab946431e6fa9a3 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Sun, 13 Mar 2022 22:04:38 +0800 Subject: [PATCH 15/71] op3 candidate should be different from op1 and op2 --- src/coreclr/jit/lsraxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 38757f0af6367..e79f7f1dbae19 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2219,7 +2219,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); srcCount += BuildOperandUses(op2, RBM_EDX); - srcCount += BuildOperandUses(op3); + srcCount += BuildOperandUses(op3, allRegs(TYP_INT) & ~(RBM_EAX | RBM_EDX)); // result put in EAX and EDX BuildDef(intrinsicTree, RBM_EAX, 0); From 3182ed8face1129d6d8f267f1819d0a5f69599e1 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 14 Mar 2022 14:27:22 +0800 Subject: [PATCH 16/71] Add guard over AsHWIntrinsic --- src/coreclr/jit/gentree.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 8dff4e46a6a9e..1026de5f373cc 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -8130,6 +8130,7 @@ inline var_types GenTree::GetRegTypeByIndex(int regIndex) const #endif // !defined(TARGET_64BIT) #endif // FEATURE_MULTIREG_RET +#ifdef FEATURE_HW_INTRINSICS if (OperIsHWIntrinsic()) { assert(TypeGet() == TYP_STRUCT); @@ -8149,6 +8150,7 @@ inline var_types GenTree::GetRegTypeByIndex(int regIndex) const return AsHWIntrinsic()->Op(1)->TypeGet(); #endif } +#endif // FEATURE_HW_INTRINSICS if (OperIsScalarLocal()) { From 48c12a419eb8f7a91815665f68c14c432cc35491 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 14 Mar 2022 17:11:12 +0800 Subject: [PATCH 17/71] Disable DivRem intrinsic use for Mono --- .../System.Private.CoreLib/src/System/Math.cs | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 0e1218682018e..4247bbedf9b50 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -317,11 +317,14 @@ public static int DivRem(int a, int b, out int result) // Restore to using % and / when the JIT is able to eliminate one of the idivs. // In the meantime, a * and - is measurably faster than an extra /. + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { (int quitient, result) = X86Base.DivRem((uint)a, a >> 31, b); return quitient; } +#endif int div = a / b; result = a - (div * b); @@ -330,11 +333,14 @@ public static int DivRem(int a, int b, out int result) public static long DivRem(long a, long b, out long result) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.X64.IsSupported) { (long quitient, result) = X86Base.X64.DivRem((ulong)a, a >> 63, b); return quitient; } +#endif long div = a / b; result = a - (div * b); @@ -350,12 +356,15 @@ public static long DivRem(long a, long b, out long result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { int dividend = left; (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); return ((sbyte)quitient, (sbyte)remainder); } +#endif sbyte quotient = (sbyte)(left / right); return (quotient, (sbyte)(left - (quotient * right))); @@ -369,11 +378,14 @@ public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); return ((byte)quitient, (byte)remainder); } +#endif byte quotient = (byte)(left / right); return (quotient, (byte)(left - (quotient * right))); @@ -387,12 +399,15 @@ public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (short Quotient, short Remainder) DivRem(short left, short right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { int dividend = left; (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); return ((short)quitient, (short)remainder); } +#endif short quotient = (short)(left / right); return (quotient, (short)(left - (quotient * right))); @@ -407,11 +422,14 @@ public static (short Quotient, short Remainder) DivRem(short left, short right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); return ((ushort)quitient, (ushort)remainder); } +#endif ushort quotient = (ushort)(left / right); return (quotient, (ushort)(left - (quotient * right))); @@ -425,10 +443,13 @@ public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort rig [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (int Quotient, int Remainder) DivRem(int left, int right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { return X86Base.DivRem((uint)left, left >> 31, right); } +#endif int quotient = left / right; return (quotient, left - (quotient * right)); @@ -443,10 +464,13 @@ public static (int Quotient, int Remainder) DivRem(int left, int right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { return X86Base.DivRem(left, 0u, right); } +#endif uint quotient = left / right; return (quotient, left - (quotient * right)); @@ -460,10 +484,13 @@ public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (long Quotient, long Remainder) DivRem(long left, long right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.X64.IsSupported) { return X86Base.X64.DivRem((ulong)left, left >> 63, right); } +#endif long quotient = left / right; return (quotient, left - (quotient * right)); @@ -478,10 +505,13 @@ public static (long Quotient, long Remainder) DivRem(long left, long right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.X64.IsSupported) { return X86Base.X64.DivRem(left, 0ul, right); } +#endif ulong quotient = left / right; return (quotient, left - (quotient * right)); @@ -495,10 +525,13 @@ public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { return X86Base.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); } +#endif nint quotient = left / right; return (quotient, left - (quotient * right)); @@ -513,10 +546,13 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { + // TODO: implement DivRem intrinsic for Mono +#if !MONO if (X86Base.IsSupported) { return X86Base.DivRem(left, (nuint)0, right); } +#endif nuint quotient = left / right; return (quotient, left - (quotient * right)); From be5b33ce8c706973c0e23f8983c745053bd2d45f Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 15 Mar 2022 10:48:09 +0800 Subject: [PATCH 18/71] Fix LSRA and invalid assertion --- src/coreclr/jit/hwintrinsiccodegenxarch.cpp | 8 ++++++-- src/coreclr/jit/lsraxarch.cpp | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp index 4a7e0474afb29..8e8c01927e585 100644 --- a/src/coreclr/jit/hwintrinsiccodegenxarch.cpp +++ b/src/coreclr/jit/hwintrinsiccodegenxarch.cpp @@ -1197,8 +1197,12 @@ void CodeGen::genX86BaseIntrinsic(GenTreeHWIntrinsic* node) // op1: EAX, op2: EDX, op3: free assert(op1Reg != REG_EDX); assert(op2Reg != REG_EAX); - assert(op3Reg != REG_EDX); - assert(op3Reg != REG_EAX); + if (op3->isUsedFromReg()) + { + assert(op3Reg != REG_EDX); + assert(op3Reg != REG_EAX); + } + emit->emitIns_Mov(INS_mov, attr, REG_EAX, op1Reg, /* canSkip */ true); emit->emitIns_Mov(INS_mov, attr, REG_EDX, op2Reg, /* canSkip */ true); diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index e79f7f1dbae19..a9c3f057f0b99 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2219,7 +2219,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); srcCount += BuildOperandUses(op2, RBM_EDX); - srcCount += BuildOperandUses(op3, allRegs(TYP_INT) & ~(RBM_EAX | RBM_EDX)); + srcCount += op3->isContained() ? BuildOperandUses(op3) : BuildDelayFreeUses(op3, op1); // result put in EAX and EDX BuildDef(intrinsicTree, RBM_EAX, 0); From d86819444582d79d4cc0641006345b074856091b Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 15 Mar 2022 11:15:19 +0800 Subject: [PATCH 19/71] Set RWM information correctly, although totally unused. --- src/coreclr/jit/gentree.cpp | 2 ++ src/coreclr/jit/hwintrinsiclistxarch.h | 4 ++-- src/coreclr/jit/lsraxarch.cpp | 2 +- 3 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 8350e7ad725fb..f3a3c65d7a7c0 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17956,6 +17956,8 @@ bool GenTree::isRMWHWIntrinsic(Compiler* comp) case NI_FMA_MultiplySubtractNegated: case NI_FMA_MultiplySubtractNegatedScalar: case NI_FMA_MultiplySubtractScalar: + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: { return true; } diff --git a/src/coreclr/jit/hwintrinsiclistxarch.h b/src/coreclr/jit/hwintrinsiclistxarch.h index 475ad7f34a5a7..4e88584f7c37d 100644 --- a/src/coreclr/jit/hwintrinsiclistxarch.h +++ b/src/coreclr/jit/hwintrinsiclistxarch.h @@ -224,7 +224,7 @@ HARDWARE_INTRINSIC(Vector256, Xor, HARDWARE_INTRINSIC(X86Base, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base, Pause, 0, 0, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid}, HW_Category_Special, HW_Flag_NoContainment|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags @@ -233,7 +233,7 @@ HARDWARE_INTRINSIC(X86Base, DivRem, // X86Base 64-bit-only Intrinsics HARDWARE_INTRINSIC(X86Base_X64, BitScanForward, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsf, INS_bsf, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) HARDWARE_INTRINSIC(X86Base_X64, BitScanReverse, 0, 1, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_bsr, INS_bsr, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics) -HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_NoRMWSemantics|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) +HARDWARE_INTRINSIC(X86Base_X64, DivRem, 0, 3, {INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_invalid, INS_idiv, INS_div, INS_invalid, INS_invalid}, HW_Category_Scalar, HW_Flag_NoFloatingPointUsed|HW_Flag_BaseTypeFromSecondArg|HW_Flag_MultiReg|HW_Flag_SpecialImport|HW_Flag_SpecialCodeGen) // *************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************************** // ISA Function name SIMD size NumArg Instructions Category Flags diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index a9c3f057f0b99..36131eb497a7d 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2214,7 +2214,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { assert(numArgs == 3); assert(dstCount == 2); - assert(!isRMW); + assert(isRMW); // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); From ff65608bbfdd6c586fb5e6001e1ea0a484b3508d Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Tue, 15 Mar 2022 13:42:22 +0800 Subject: [PATCH 20/71] Move multi-reg temp allocation to common helper --- src/coreclr/jit/compiler.h | 2 ++ src/coreclr/jit/gentree.cpp | 18 ++++++++++++++++++ src/coreclr/jit/hwintrinsicarm64.cpp | 18 +++--------------- src/coreclr/jit/hwintrinsicxarch.cpp | 13 +------------ 4 files changed, 24 insertions(+), 27 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index e4f71377d0114..b3e45f07fc110 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3357,6 +3357,8 @@ class Compiler NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID); + GenTreeLclVar* gtNewLclvForMultiRegIntrinsicNode(GenTreeHWIntrinsic* intrinsicNode, CORINFO_SIG_INFO* sig); + CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, CorInfoType simdBaseJitType); CorInfoType getBaseJitTypeFromArgIfNeeded(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index f3a3c65d7a7c0..8935c091b4cf0 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -21637,6 +21637,24 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( /* isSimdAsHWIntrinsic */ false, op1, op2, op3); } +GenTreeLclVar* Compiler::gtNewLclvForMultiRegIntrinsicNode(GenTreeHWIntrinsic* intrinsicNode, CORINFO_SIG_INFO* sig) +{ + assert(HWIntrinsicInfo::IsMultiReg(intrinsicNode->GetHWIntrinsicId())); + + const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); + impAssignTempGen(lclNum, intrinsicNode, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); + + LclVarDsc* varDsc = lvaGetDesc(lclNum); + // The following is to exclude the fields of the local to have SSA. + varDsc->lvIsMultiRegRet = true; + + GenTreeLclVar* lclVar = gtNewLclvNode(lclNum, varDsc->lvType); + lclVar->SetDoNotCSE(); + lclVar->SetMultiReg(); + + return lclVar; +} + // Returns true for the HW Intrinsic instructions that have MemoryLoad semantics, false otherwise bool GenTreeHWIntrinsic::OperIsMemoryLoad() const { diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index f1ac37611c5f8..13c136fd2fe58 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1582,27 +1582,15 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, } } - GenTree* loadIntrinsic = gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseJitType, simdSize); + GenTreeHWIntrinsic* loadIntrinsic = + gtNewSimdHWIntrinsicNode(retType, op1, intrinsic, simdBaseJitType, simdSize); // This operation contains an implicit indirection // it could point into the global heap or // it could throw a null reference exception. // loadIntrinsic->gtFlags |= (GTF_GLOB_REF | GTF_EXCEPT); - assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); - - const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); - impAssignTempGen(lclNum, loadIntrinsic, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); - - LclVarDsc* varDsc = lvaGetDesc(lclNum); - // The following is to exclude the fields of the local to have SSA. - varDsc->lvIsMultiRegRet = true; - - GenTreeLclVar* lclVar = gtNewLclvNode(lclNum, varDsc->lvType); - lclVar->SetDoNotCSE(); - lclVar->SetMultiReg(); - - retNode = lclVar; + retNode = gtNewLclvForMultiRegIntrinsicNode(loadIntrinsic, sig); break; } diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index d68a5a724b97b..f962d32a750ac 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2243,18 +2243,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, // Store the type from signature into SIMD base type for convenience divRemIntrinsic->SetSimdBaseJitType(simdBaseJitType); - const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); - impAssignTempGen(lclNum, divRemIntrinsic, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); - - LclVarDsc* varDsc = lvaGetDesc(lclNum); - // The following is to exclude the fields of the local to have SSA. - varDsc->lvIsMultiRegRet = true; - - GenTreeLclVar* lclVar = gtNewLclvNode(lclNum, varDsc->lvType); - lclVar->SetDoNotCSE(); - lclVar->SetMultiReg(); - - retNode = lclVar; + retNode = gtNewLclvForMultiRegIntrinsicNode(divRemIntrinsic, sig); break; } From b31f896d6f7294866a555dda96fd3627a5633d69 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 16 Mar 2022 23:22:08 +0800 Subject: [PATCH 21/71] Disable DivRem intrinsic test for Mono. --- src/tests/issues.targets | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index a6b04860c4f5b..a6d533a598055 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1411,6 +1411,12 @@ https://github.com/dotnet/runtime/issues/54185 + + https://github.com/dotnet/runtime/pull/66551#issuecomment-1066120794 + + + https://github.com/dotnet/runtime/pull/66551#issuecomment-1066120794 + From 0bd13276e04a80c4804a6f2c44ec3272a68020c4 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Wed, 23 Mar 2022 14:44:02 +0800 Subject: [PATCH 22/71] Fix typo of quotient --- .../System.Private.CoreLib/src/System/Math.cs | 24 +++++++++---------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 4247bbedf9b50..40410edb8831e 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -321,8 +321,8 @@ public static int DivRem(int a, int b, out int result) #if !MONO if (X86Base.IsSupported) { - (int quitient, result) = X86Base.DivRem((uint)a, a >> 31, b); - return quitient; + (int quotient, result) = X86Base.DivRem((uint)a, a >> 31, b); + return quotient; } #endif @@ -337,8 +337,8 @@ public static long DivRem(long a, long b, out long result) #if !MONO if (X86Base.X64.IsSupported) { - (long quitient, result) = X86Base.X64.DivRem((ulong)a, a >> 63, b); - return quitient; + (long quotient, result) = X86Base.X64.DivRem((ulong)a, a >> 63, b); + return quotient; } #endif @@ -361,8 +361,8 @@ public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) if (X86Base.IsSupported) { int dividend = left; - (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); - return ((sbyte)quitient, (sbyte)remainder); + (int q, int r) = X86Base.DivRem((uint)dividend, dividend >> 31, right); + return ((sbyte)q, (sbyte)r); } #endif @@ -382,8 +382,8 @@ public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) #if !MONO if (X86Base.IsSupported) { - (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); - return ((byte)quitient, (byte)remainder); + (uint q, uint r) = X86Base.DivRem(left, 0u, right); + return ((byte)q, (byte)r); } #endif @@ -404,8 +404,8 @@ public static (short Quotient, short Remainder) DivRem(short left, short right) if (X86Base.IsSupported) { int dividend = left; - (int quitient, int remainder) = X86Base.DivRem((uint)dividend, dividend >> 31, right); - return ((short)quitient, (short)remainder); + (int q, int r) = X86Base.DivRem((uint)dividend, dividend >> 31, right); + return ((short)q, (short)r); } #endif @@ -426,8 +426,8 @@ public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort rig #if !MONO if (X86Base.IsSupported) { - (uint quitient, uint remainder) = X86Base.DivRem(left, 0u, right); - return ((ushort)quitient, (ushort)remainder); + (uint q, uint r) = X86Base.DivRem(left, 0u, right); + return ((ushort)q, (ushort)r); } #endif From 43049a9691b7ea907401ef5937cbbf0038e52cfc Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Sep 2022 13:26:33 +0800 Subject: [PATCH 23/71] Use impAssignMultiRegTypeToVar --- src/coreclr/jit/compiler.h | 4 +--- src/coreclr/jit/gentree.cpp | 18 ------------------ src/coreclr/jit/hwintrinsicarm64.cpp | 3 ++- src/coreclr/jit/hwintrinsicxarch.cpp | 3 ++- src/coreclr/jit/importer.cpp | 4 ++-- 5 files changed, 7 insertions(+), 25 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 07fa7026a210f..cc697583b32f1 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1871,7 +1871,7 @@ class Compiler DWORD expensiveDebugCheckLevel; #endif -#if FEATURE_MULTIREG_RET +#if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass DEBUGARG(CorInfoCallConvExtension callConv)); #endif // FEATURE_MULTIREG_RET @@ -2575,8 +2575,6 @@ class Compiler NamedIntrinsic hwIntrinsicID); GenTreeHWIntrinsic* gtNewScalarHWIntrinsicNode( var_types type, GenTree* op1, GenTree* op2, GenTree* op3, NamedIntrinsic hwIntrinsicID); - GenTreeLclVar* gtNewLclvForMultiRegIntrinsicNode(GenTreeHWIntrinsic* intrinsicNode, CORINFO_SIG_INFO* sig); - CORINFO_CLASS_HANDLE gtGetStructHandleForHWSIMD(var_types simdType, CorInfoType simdBaseJitType); CorInfoType getBaseJitTypeFromArgIfNeeded(NamedIntrinsic intrinsic, CORINFO_CLASS_HANDLE clsHnd, diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 7214dc4f5a5a6..799be4ad6d371 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -22682,24 +22682,6 @@ GenTreeHWIntrinsic* Compiler::gtNewScalarHWIntrinsicNode( /* isSimdAsHWIntrinsic */ false, op1, op2, op3); } -GenTreeLclVar* Compiler::gtNewLclvForMultiRegIntrinsicNode(GenTreeHWIntrinsic* intrinsicNode, CORINFO_SIG_INFO* sig) -{ - assert(HWIntrinsicInfo::IsMultiReg(intrinsicNode->GetHWIntrinsicId())); - - const unsigned lclNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg intrinsic")); - impAssignTempGen(lclNum, intrinsicNode, sig->retTypeSigClass, (unsigned)CHECK_SPILL_ALL); - - LclVarDsc* varDsc = lvaGetDesc(lclNum); - // The following is to exclude the fields of the local to have SSA. - varDsc->lvIsMultiRegRet = true; - - GenTreeLclVar* lclVar = gtNewLclvNode(lclNum, varDsc->lvType); - lclVar->SetDoNotCSE(); - lclVar->SetMultiReg(); - - return lclVar; -} - //------------------------------------------------------------------------ // OperIsMemoryLoad: Does this HWI node have memory load semantics? // diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 82187f04f377f..5ed2a5b0dab3f 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1808,7 +1808,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // loadIntrinsic->gtFlags |= (GTF_GLOB_REF | GTF_EXCEPT); - retNode = gtNewLclvForMultiRegIntrinsicNode(loadIntrinsic, sig); + retNode = impAssignMultiRegTypeToVar(loadIntrinsic, + sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); break; } diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 64e5811de6881..84d6f33edf007 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2523,7 +2523,8 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, // Store the type from signature into SIMD base type for convenience divRemIntrinsic->SetSimdBaseJitType(simdBaseJitType); - retNode = gtNewLclvForMultiRegIntrinsicNode(divRemIntrinsic, sig); + retNode = impAssignMultiRegTypeToVar(divRemIntrinsic, + sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); break; } diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 1e85471512baf..6c79dabbb0ed2 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -17735,7 +17735,7 @@ void Compiler::impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* src, CORINFO } #endif // TARGET_ARM -#if FEATURE_MULTIREG_RET +#if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // impAssignMultiRegTypeToVar: ensure calls that return structs in multiple // registers return values to suitable temps. @@ -17757,7 +17757,7 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, // TODO-1stClassStructs: Handle constant propagation and CSE-ing of multireg returns. ret->gtFlags |= GTF_DONT_CSE; - assert(IsMultiRegReturnedType(hClass, callConv)); + assert(IsMultiRegReturnedType(hClass, callConv) || op->IsMultiRegNode()); // Mark the var so that fields are not promoted and stay together. lvaTable[tmpNum].lvIsMultiRegRet = true; From d485b61c94bc1fa7542c0a52db264e7826e836d6 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Sep 2022 13:28:54 +0800 Subject: [PATCH 24/71] Update #ifdef --- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/lower.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index cc697583b32f1..1e1aa0b7b76ff 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1874,7 +1874,7 @@ class Compiler #if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass DEBUGARG(CorInfoCallConvExtension callConv)); -#endif // FEATURE_MULTIREG_RET +#endif // FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) #ifdef TARGET_X86 bool isTrivialPointerSizedStruct(CORINFO_CLASS_HANDLE clsHnd) const; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 6c79dabbb0ed2..e5a822973be1e 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -17764,7 +17764,7 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, return ret; } -#endif // FEATURE_MULTIREG_RET +#endif // FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // impReturnInstruction: import a return or an explicit tail call diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 9830b696ac79a..2d158c4b91a7c 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6785,7 +6785,7 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc) { bool canEnregister = false; -#if FEATURE_MULTIREG_RET || FEATURE_HW_INTRINSICS +#if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) LclVarDsc* varDsc = comp->lvaGetDesc(lclNode->GetLclNum()); if ((comp->lvaEnregMultiRegVars) && varDsc->lvPromoted) { From aeb114ac5d89441bd6b3a5ba173d9780de267700 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Mon, 19 Sep 2022 15:06:18 +0800 Subject: [PATCH 25/71] Remove change in LowerBlockStore --- src/coreclr/jit/lowerxarch.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index c025951730930..6301c39e40812 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -367,16 +367,6 @@ void Lowering::LowerBlockStore(GenTreeBlk* blkNode) ContainBlockStoreAddress(blkNode, size, dstAddr); } - else if (src->OperIsHWIntrinsic()) - { - assert(!blkNode->AsObj()->GetLayout()->HasGCPtr()); - if (blkNode->OperIs(GT_STORE_OBJ)) - { - blkNode->SetOper(GT_STORE_BLK); - } - blkNode->gtBlkOpKind = GenTreeBlk::BlkOpKindUnroll; - ContainBlockStoreAddress(blkNode, size, dstAddr); - } else { assert(blkNode->OperIs(GT_STORE_BLK, GT_STORE_DYN_BLK)); From aa57f260000c711f93702168214c41e123a656f6 Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 23 Sep 2022 14:26:32 +0800 Subject: [PATCH 26/71] Adjust assert and helper method --- src/coreclr/jit/hwintrinsicarm64.cpp | 1 + src/coreclr/jit/importer.cpp | 6 +++--- src/coreclr/jit/lsraxarch.cpp | 3 ++- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicarm64.cpp b/src/coreclr/jit/hwintrinsicarm64.cpp index 5ed2a5b0dab3f..c5070786199d2 100644 --- a/src/coreclr/jit/hwintrinsicarm64.cpp +++ b/src/coreclr/jit/hwintrinsicarm64.cpp @@ -1808,6 +1808,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, // loadIntrinsic->gtFlags |= (GTF_GLOB_REF | GTF_EXCEPT); + assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); retNode = impAssignMultiRegTypeToVar(loadIntrinsic, sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); break; diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e5a822973be1e..11697eb4a207d 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -17752,15 +17752,15 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, { unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return")); impAssignTempGen(tmpNum, op, hClass, CHECK_SPILL_ALL); - GenTree* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); + GenTreeLclVar* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); // TODO-1stClassStructs: Handle constant propagation and CSE-ing of multireg returns. - ret->gtFlags |= GTF_DONT_CSE; + ret->SetDoNotCSE(); assert(IsMultiRegReturnedType(hClass, callConv) || op->IsMultiRegNode()); // Mark the var so that fields are not promoted and stay together. - lvaTable[tmpNum].lvIsMultiRegRet = true; + ret->SetMultiReg(); return ret; } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 8ef0742c5e82f..c8aa52c192665 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2496,7 +2496,8 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou else { // Currently dstCount = 2 is only used for DivRem, which has special constriants and handled above - assert((dstCount == 0) || (dstCount == 2)); + assert((dstCount == 0) || + (dstCount == 2) && ((intrinsicId == NI_X86Base_DivRem) || (intrinsicId == NI_X86Base_X64_DivRem))); } *pDstCount = dstCount; From 9345e5791e572e60b55bb3b31a5de6170fbb82ec Mon Sep 17 00:00:00 2001 From: Huo Yaoyuan Date: Fri, 23 Sep 2022 15:59:13 +0800 Subject: [PATCH 27/71] Update CheckMultiRegLclVar --- src/coreclr/jit/lower.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 2d158c4b91a7c..0f9f051f9c38c 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6815,8 +6815,9 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* // For local stores on XARCH we can't handle another lclVar source. // If the source was another lclVar similarly promoted, we would // have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) + if (lclNode->OperIs(GT_STORE_LCL_VAR) && !lclNode->gtGetOp1()->OperIs(GT_CALL)) { + assert(lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)); canEnregister = false; } #endif // TARGET_XARCH From 65c0af67b66c71989e62c5d653339d1a51982347 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 23 Sep 2022 07:26:08 -0700 Subject: [PATCH 28/71] fix build errors --- src/coreclr/jit/importer.cpp | 8 +++++++- src/coreclr/jit/lower.cpp | 3 +-- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 11697eb4a207d..3d0598e7879ad 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -17752,7 +17752,13 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, { unsigned tmpNum = lvaGrabTemp(true DEBUGARG("Return value temp for multireg return")); impAssignTempGen(tmpNum, op, hClass, CHECK_SPILL_ALL); - GenTreeLclVar* ret = gtNewLclvNode(tmpNum, lvaTable[tmpNum].lvType); + + LclVarDsc* varDsc = lvaGetDesc(tmpNum); + + // The following is to exclude the fields of the local to have SSA. + varDsc->lvIsMultiRegRet = true; + + GenTreeLclVar* ret = gtNewLclvNode(tmpNum, varDsc->lvType); // TODO-1stClassStructs: Handle constant propagation and CSE-ing of multireg returns. ret->SetDoNotCSE(); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 0f9f051f9c38c..2d158c4b91a7c 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6815,9 +6815,8 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* // For local stores on XARCH we can't handle another lclVar source. // If the source was another lclVar similarly promoted, we would // have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && !lclNode->gtGetOp1()->OperIs(GT_CALL)) + if (lclNode->OperIs(GT_STORE_LCL_VAR) && lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) { - assert(lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)); canEnregister = false; } #endif // TARGET_XARCH From df922de3ce0d42365d1c789c842c28bcc2c30243 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Nov 2022 07:49:06 -0800 Subject: [PATCH 29/71] Fix some merge conflicts --- src/coreclr/jit/compiler.h | 2 -- src/coreclr/jit/gentree.cpp | 5 +++++ src/coreclr/jit/importer.cpp | 2 -- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 76aa7bf4e4fdb..ba5db04e9ac54 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -1926,10 +1926,8 @@ class Compiler DWORD expensiveDebugCheckLevel; #endif -#if defined(FEATURE_HW_INTRINSICS) GenTree* impAssignMultiRegTypeToVar(GenTree* op, CORINFO_CLASS_HANDLE hClass DEBUGARG(CorInfoCallConvExtension callConv)); -#endif // defined(FEATURE_HW_INTRINSICS) #ifdef TARGET_X86 bool isTrivialPointerSizedStruct(CORINFO_CLASS_HANDLE clsHnd) const; diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 1fe642bc60226..a99a5ae2efa20 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23132,6 +23132,11 @@ ClassLayout* GenTreeHWIntrinsic::GetLayout(Compiler* compiler) const switch (GetHWIntrinsicId()) { +#ifdef TARGET_XARCH + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + return compiler->typGetBlkLayout(16); +#endif #ifdef TARGET_ARM64 case NI_AdvSimd_Arm64_LoadPairScalarVector64: case NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal: diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index c5002c6901c3a..e314949e522ee 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11292,7 +11292,6 @@ void Compiler::impMarkLclDstNotPromotable(unsigned tmpNum, GenTree* src, CORINFO } #endif // TARGET_ARM -#if defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // impAssignMultiRegTypeToVar: ensure calls that return structs in multiple // registers return values to suitable temps. @@ -11327,7 +11326,6 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, return ret; } -#endif // defined(FEATURE_HW_INTRINSICS) //------------------------------------------------------------------------ // impReturnInstruction: import a return or an explicit tail call From 924fc42068296133cfbc797e15bd823a86b915de Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Nov 2022 15:37:33 -0800 Subject: [PATCH 30/71] Fix some errors --- src/coreclr/jit/gentree.cpp | 3 ++- src/coreclr/jit/importer.cpp | 3 --- .../System.Private.CoreLib/src/System/Math.cs | 18 +++++++++++++++++- 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index a99a5ae2efa20..d09a6e7a6bfdc 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23134,9 +23134,10 @@ ClassLayout* GenTreeHWIntrinsic::GetLayout(Compiler* compiler) const { #ifdef TARGET_XARCH case NI_X86Base_DivRem: + return compiler->typGetBlkLayout(8); case NI_X86Base_X64_DivRem: return compiler->typGetBlkLayout(16); -#endif +#endif // TARGET_XARCH #ifdef TARGET_ARM64 case NI_AdvSimd_Arm64_LoadPairScalarVector64: case NI_AdvSimd_Arm64_LoadPairScalarVector64NonTemporal: diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index e314949e522ee..841a6171b9c12 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -11321,9 +11321,6 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, assert(IsMultiRegReturnedType(hClass, callConv) || op->IsMultiRegNode()); - // Set "lvIsMultiRegRet" to block promotion under "!lvaEnregMultiRegVars". - ret->SetMultiReg(); - return ret; } diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 40fcdd17c94bc..5849d0c013281 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -527,11 +527,19 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { // TODO: implement DivRem intrinsic for Mono #if !MONO +#if TARGET_64BIT + if (X86Base.X64.IsSupported) + { + (long answer1, long answer2) = X86Base.X64.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); + return ((nint)answer1, (nint)answer2); + } +#else if (X86Base.IsSupported) { return X86Base.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); } -#endif +#endif // TARGET_64BIT +#endif // !MONO nint quotient = left / right; return (quotient, left - (quotient * right)); @@ -548,10 +556,18 @@ public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { // TODO: implement DivRem intrinsic for Mono #if !MONO +#if TARGET_64BIT + if (X86Base.X64.IsSupported) + { + (ulong answer1, ulong answer2) = X86Base.X64.DivRem(left, (nuint)0, right); + return ((nuint)answer1, (nuint)answer2); + } +#else if (X86Base.IsSupported) { return X86Base.DivRem(left, (nuint)0, right); } +#endif // TARGET_64BIT #endif nuint quotient = left / right; From 1e7ff056b23e4eee40849f226d516a1b9ab5240a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Nov 2022 18:33:14 -0800 Subject: [PATCH 31/71] Fix GCC build error --- src/coreclr/jit/lsraxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 4a32ba5f0dc7b..c8cf89307d08c 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2500,7 +2500,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { // Currently dstCount = 2 is only used for DivRem, which has special constriants and handled above assert((dstCount == 0) || - (dstCount == 2) && ((intrinsicId == NI_X86Base_DivRem) || (intrinsicId == NI_X86Base_X64_DivRem))); + ((dstCount == 2) && ((intrinsicId == NI_X86Base_DivRem) || (intrinsicId == NI_X86Base_X64_DivRem)))); } *pDstCount = dstCount; From 62e6c5916041d4c05dacbe9d67ffc2d30c9bae3f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Nov 2022 18:35:01 -0800 Subject: [PATCH 32/71] jit format --- src/coreclr/jit/lower.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index ba5b73044273b..745d128d37aef 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6870,7 +6870,8 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* #ifdef TARGET_XARCH // For local stores on XARCH we can't handle another lclVar source. // If the source was another lclVar similarly promoted, we would have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) + if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && + lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) { canEnregister = false; } From a1b480217e72f5b7bcce1566e8a132566a9026f2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 7 Nov 2022 19:07:38 -0800 Subject: [PATCH 33/71] Make the size depending on the struct --- src/coreclr/jit/gentree.cpp | 2 +- .../System.Private.CoreLib/src/System/Math.cs | 16 ---------------- 2 files changed, 1 insertion(+), 17 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index d09a6e7a6bfdc..255dac97012fe 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -23134,7 +23134,7 @@ ClassLayout* GenTreeHWIntrinsic::GetLayout(Compiler* compiler) const { #ifdef TARGET_XARCH case NI_X86Base_DivRem: - return compiler->typGetBlkLayout(8); + return compiler->typGetBlkLayout(genTypeSize(GetSimdBaseType()) * 2); case NI_X86Base_X64_DivRem: return compiler->typGetBlkLayout(16); #endif // TARGET_XARCH diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 5849d0c013281..ddcfac7daecc9 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -527,18 +527,10 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { // TODO: implement DivRem intrinsic for Mono #if !MONO -#if TARGET_64BIT - if (X86Base.X64.IsSupported) - { - (long answer1, long answer2) = X86Base.X64.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); - return ((nint)answer1, (nint)answer2); - } -#else if (X86Base.IsSupported) { return X86Base.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); } -#endif // TARGET_64BIT #endif // !MONO nint quotient = left / right; @@ -556,18 +548,10 @@ public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { // TODO: implement DivRem intrinsic for Mono #if !MONO -#if TARGET_64BIT - if (X86Base.X64.IsSupported) - { - (ulong answer1, ulong answer2) = X86Base.X64.DivRem(left, (nuint)0, right); - return ((nuint)answer1, (nuint)answer2); - } -#else if (X86Base.IsSupported) { return X86Base.DivRem(left, (nuint)0, right); } -#endif // TARGET_64BIT #endif nuint quotient = left / right; From 8199acbf39bed3472f096e251dd133f1966a6b34 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 6 Dec 2022 11:43:59 -0800 Subject: [PATCH 34/71] Fix the formatting of summary --- .../Intrinsics/X86/X86Base.PlatformNotSupported.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs index de80c986c0b14..200b8dce3404f 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -88,18 +88,11 @@ internal X64() { } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw new PlatformNotSupportedException(); } /// - /// void _mm_pause (void); - /// PAUSE - /// - public static void Pause() { throw new PlatformNotSupportedException(); } - - /// DIV reg/m32 /// public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw new PlatformNotSupportedException(); } /// - /// int _div64(__int64 dividend, int divisor, int* remainder) /// IDIV reg/m32 /// public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw new PlatformNotSupportedException(); } @@ -114,6 +107,12 @@ internal X64() { } /// public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw new PlatformNotSupportedException(); } + /// + /// void _mm_pause (void); + /// PAUSE + /// + public static void Pause() { throw new PlatformNotSupportedException(); } + #pragma warning restore IDE0060 } From ed12edb9762623581a0cf38393fe9e547844437c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 6 Dec 2022 20:44:23 -0800 Subject: [PATCH 35/71] Remove trailing spaces --- .../Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs index 200b8dce3404f..ba25f79678146 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.PlatformNotSupported.cs @@ -106,7 +106,7 @@ internal X64() { } /// IDIV reg/m /// public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw new PlatformNotSupportedException(); } - + /// /// void _mm_pause (void); /// PAUSE From 532a8fda3b5b18f00abadeedd2807e35d5235fb7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 7 Dec 2022 10:16:05 -0800 Subject: [PATCH 36/71] Fix the tests to adopt new model --- .../X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs | 6 ++++-- .../X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs | 6 ++++-- .../X86/X86Base.X64/Program.X86Base.X64.cs | 7 ++----- .../X86/X86Base.X64/X86Base.X64_r.csproj | 3 ++- .../X86/X86Base.X64/X86Base.X64_ro.csproj | 3 ++- .../X86/X86Base/DivRem.Int32.Tuple3Op.cs | 6 ++++-- .../X86/X86Base/DivRem.UInt32.Tuple3Op.cs | 6 ++++-- .../X86/X86Base/DivRem.nint.Tuple3Op.cs | 6 ++++-- .../X86/X86Base/DivRem.nuint.Tuple3Op.cs | 6 ++++-- .../HardwareIntrinsics/X86/X86Base/Program.X86Base.cs | 9 ++------- .../JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj | 3 ++- .../JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj | 3 ++- 12 files changed, 36 insertions(+), 28 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs index 528b77c934475..b5ac75c2a74b7 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program { - private static void DivRemInt64Tuple3Op() + [Fact] + public static void DivRemInt64Tuple3Op() { var test = new ScalarTernOpTupleTest__DivRemInt64(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs index 186632f1654b0..61c83017ab64d 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program { - private static void DivRemUInt64Tuple3Op() + [Fact] + public static void DivRemUInt64Tuple3Op() { var test = new ScalarTernOpTupleTest__DivRemUInt64(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs index b8689bb232f71..7ffd2b030af9c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -4,16 +4,13 @@ using System; using System.Collections.Generic; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program { static Program() { - TestList = new Dictionary() { - ["DivRem.Int64.Tuple3Op"] = DivRemInt64Tuple3Op, - ["DivRem.UInt64.Tuple3Op"] = DivRemUInt64Tuple3Op, - }; + } } } diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index 4fca0c12394a8..b202e642b9f79 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -1,6 +1,7 @@ - Exe + X86_X86Base.X64_r + false true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index 8e189c9d253a4..0004c59c1a875 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -1,6 +1,7 @@ - Exe + X86_X86Base.X64_ro + false true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs index 3667a0c84a23e..f4ce4d38c603a 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program { - private static void DivRemInt32Tuple3Op() + [Fact] + public static void DivRemInt32Tuple3Op() { var test = new ScalarTernOpTupleTest__DivRemInt32(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs index e94ff31851325..1b17608374efc 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program { - private static void DivRemUInt32Tuple3Op() + [Fact] + public static void DivRemUInt32Tuple3Op() { var test = new ScalarTernOpTupleTest__DivRemUInt32(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs index 93ea93ca70fcf..249ba238b7533 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program { - private static void DivRemnintTuple3Op() + [Fact] + public static void DivRemnintTuple3Op() { var test = new ScalarTernOpTupleTest__DivRemnint(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs index 941bb943f9e75..0e49b4d1cf9d1 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs @@ -13,12 +13,14 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using Xunit; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program { - private static void DivRemnuintTuple3Op() + [Fact] + public static void DivRemnuintTuple3Op() { var test = new ScalarTernOpTupleTest__DivRemnuint(); diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs index 5f5273de801c5..129d7b046036c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -4,18 +4,13 @@ using System; using System.Collections.Generic; -namespace JIT.HardwareIntrinsics.X86 +namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program { static Program() { - TestList = new Dictionary() { - ["DivRem.Int32.Tuple3Op"] = DivRemInt32Tuple3Op, - ["DivRem.UInt32.Tuple3Op"] = DivRemUInt32Tuple3Op, - ["DivRem.nint.Tuple3Op"] = DivRemnintTuple3Op, - ["DivRem.nuint.Tuple3Op"] = DivRemnuintTuple3Op, - }; + } } } diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index 7010a8f041733..c1e57a2b1b74c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -1,6 +1,7 @@ - Exe + X86_X86Base_r + false true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 51030e1812d5a..d10a42e110a6b 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -1,6 +1,7 @@ - Exe + X86_X86Base_ro + false true From 281c1b0bc3e1accb3f084d8f0654a6d27453cd9f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 8 Dec 2022 13:46:13 -0800 Subject: [PATCH 37/71] Fix MAX_RET_REG_COUNT -> MAX_MULTIREG_COUNT --- src/coreclr/jit/gentree.h | 20 ++++++++++---------- src/coreclr/jit/lsra.h | 2 +- 2 files changed, 11 insertions(+), 11 deletions(-) diff --git a/src/coreclr/jit/gentree.h b/src/coreclr/jit/gentree.h index 27f37e332dd45..ce7f87f93e60b 100644 --- a/src/coreclr/jit/gentree.h +++ b/src/coreclr/jit/gentree.h @@ -3711,8 +3711,8 @@ static const unsigned PACKED_GTF_SPILLED = 2; // inline GenTreeFlags GetMultiRegSpillFlagsByIdx(MultiRegSpillFlags flags, unsigned idx) { - static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); - assert(idx < MAX_RET_REG_COUNT); + static_assert_no_msg(MAX_MULTIREG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); + assert(idx < MAX_MULTIREG_COUNT); unsigned bits = flags >> (idx * 2); // It doesn't matter that we possibly leave other high bits here. GenTreeFlags spillFlags = GTF_EMPTY; @@ -3743,8 +3743,8 @@ inline GenTreeFlags GetMultiRegSpillFlagsByIdx(MultiRegSpillFlags flags, unsigne // inline MultiRegSpillFlags SetMultiRegSpillFlagsByIdx(MultiRegSpillFlags oldFlags, GenTreeFlags flagsToSet, unsigned idx) { - static_assert_no_msg(MAX_RET_REG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); - assert(idx < MAX_RET_REG_COUNT); + static_assert_no_msg(MAX_MULTIREG_COUNT * 2 <= sizeof(unsigned char) * BITS_PER_BYTE); + assert(idx < MAX_MULTIREG_COUNT); MultiRegSpillFlags newFlags = oldFlags; unsigned bits = 0; @@ -8045,7 +8045,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp // State required to support copy/reload of a multi-reg call node. // The first register is always given by GetRegNum(). // - regNumberSmall gtOtherRegs[MAX_RET_REG_COUNT - 1]; + regNumberSmall gtOtherRegs[MAX_MULTIREG_COUNT - 1]; #endif //---------------------------------------------------------- @@ -8060,7 +8060,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp void ClearOtherRegs() { #if FEATURE_MULTIREG_RET - for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i) + for (unsigned i = 0; i < MAX_MULTIREG_COUNT - 1; ++i) { gtOtherRegs[i] = REG_NA; } @@ -8078,7 +8078,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp // regNumber GetRegNumByIdx(unsigned idx) const { - assert(idx < MAX_RET_REG_COUNT); + assert(idx < MAX_MULTIREG_COUNT); if (idx == 0) { @@ -8104,7 +8104,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp // void SetRegNumByIdx(regNumber reg, unsigned idx) { - assert(idx < MAX_RET_REG_COUNT); + assert(idx < MAX_MULTIREG_COUNT); if (idx == 0) { @@ -8141,7 +8141,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp assert(OperGet() == from->OperGet()); #ifdef UNIX_AMD64_ABI - for (unsigned i = 0; i < MAX_RET_REG_COUNT - 1; ++i) + for (unsigned i = 0; i < MAX_MULTIREG_COUNT - 1; ++i) { gtOtherRegs[i] = from->gtOtherRegs[i]; } @@ -8158,7 +8158,7 @@ struct GenTreeCopyOrReload : public GenTreeUnOp // but for COPY or RELOAD there is only a valid register for the register positions // that must be copied or reloaded. // - for (unsigned i = MAX_RET_REG_COUNT; i > 1; i--) + for (unsigned i = MAX_MULTIREG_COUNT; i > 1; i--) { if (gtOtherRegs[i - 2] != REG_NA) { diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index e30736a63fd5a..7468e500ab4ab 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -2259,7 +2259,7 @@ class RefPosition // Indicates the position of the register that this ref position refers to. // The max bits needed is based on max value of MAX_RET_REG_COUNT value // across all targets and that happened to be 4 on Arm. Hence index value - // would be 0..MAX_RET_REG_COUNT-1. + // would be 0..MAX_MULTIREG_COUNT-1. unsigned char multiRegIdx : 2; // Last Use - this may be true for multiple RefPositions in the same Interval From 97630a29c7848986ecb6cf8bcead37a67f18bc04 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 9 Dec 2022 14:29:15 -0800 Subject: [PATCH 38/71] Exclude from mono run --- .../HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs | 1 + .../X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs | 1 + .../HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs | 1 + .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj | 2 ++ .../HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj | 2 ++ .../JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs | 1 + .../HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs | 1 + .../JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs | 1 + .../JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs | 1 + src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs | 1 + src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj | 2 ++ src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj | 2 ++ 12 files changed, 16 insertions(+) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs index b5ac75c2a74b7..66be43804876e 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs index 61c83017ab64d..9a974646afed8 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs index 7ffd2b030af9c..230f3249752dc 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index b202e642b9f79..825b9cd1fef37 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -3,6 +3,8 @@ X86_X86Base.X64_r false true + + true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index 0004c59c1a875..d56fa0e16d37e 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -3,6 +3,8 @@ X86_X86Base.X64_ro false true + + true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs index f4ce4d38c603a..bbf02c95b24a7 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs index 1b17608374efc..3ff1529d566c9 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs index 249ba238b7533..ab234c1e57c76 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs index 0e49b4d1cf9d1..966bf95660950 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs @@ -15,6 +15,7 @@ using System.Runtime.Intrinsics.X86; using Xunit; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs index 129d7b046036c..d02560343f145 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index c1e57a2b1b74c..fd05cd48f1afa 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -3,6 +3,8 @@ X86_X86Base_r false true + + true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index d10a42e110a6b..1dc655eec0673 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -3,6 +3,8 @@ X86_X86Base_ro false true + + true Embedded From 491f82ede22b0f8ff15ffd966a5aea3561de841e Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 12 Dec 2022 10:28:45 -0800 Subject: [PATCH 39/71] Add RequiresProcessIsolation --- .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj | 1 + .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index 825b9cd1fef37..a8eb433b7dddb 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -5,6 +5,7 @@ true true + true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index d56fa0e16d37e..c2720a0d03708 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -5,6 +5,7 @@ true true + true Embedded From 0fc11c9525f74d5e73c6fd38fb4ca8c0c7a099f6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 6 Jan 2023 22:21:38 -0800 Subject: [PATCH 40/71] Real fix for build break --- src/coreclr/jit/lowerxarch.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index fb888828aa48f..ce930b7402ff0 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -7298,7 +7298,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) case NI_X86Base_X64_DivRem: { // DIV only allows divisor (op3) in memory - if (TryGetContainableHWIntrinsicOp(node, &op3, &supportsRegOptional)) + if (IsContainableHWIntrinsicOp(node, op3, &supportsRegOptional)) { MakeSrcContained(node, op3); } From 8ab602309c3cb9ab86b3d160b2bba0ddb0a77de8 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 11 Jan 2023 09:56:05 -0800 Subject: [PATCH 41/71] Fix the test cases to adopt to the new system --- .../X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs | 259 ------------------ .../X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs | 259 ------------------ .../X86/X86Base.X64/X86Base.X64_r.csproj | 2 - .../X86/X86Base.X64/X86Base.X64_ro.csproj | 2 - .../X86/X86Base/DivRem.Int32.Tuple3Op.cs | 259 ------------------ .../X86/X86Base/DivRem.UInt32.Tuple3Op.cs | 259 ------------------ .../X86/X86Base/DivRem.nint.Tuple3Op.cs | 259 ------------------ .../X86/X86Base/DivRem.nuint.Tuple3Op.cs | 259 ------------------ .../X86/X86Base/X86Base_r.csproj | 4 - .../X86/X86Base/X86Base_ro.csproj | 4 - 10 files changed, 1566 deletions(-) delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs delete mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs deleted file mode 100644 index 66be43804876e..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.Int64.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base.X64 -{ - public static partial class Program - { - [Fact] - public static void DivRemInt64Tuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemInt64(); - - 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 ScalarTernOpTupleTest__DivRemInt64 - { - private struct TestStruct - { - public UInt64 _fld1; - public Int64 _fld2; - public Int64 _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = UInt64.MaxValue; - testStruct._fld2 = -2; - testStruct._fld3 = -0x100000001; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemInt64 testClass) - { - var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, result); - } - } - - private static UInt64 _data1; - private static Int64 _data2; - private static Int64 _data3; - - private static UInt64 _clsVar1; - private static Int64 _clsVar2; - private static Int64 _clsVar3; - - private UInt64 _fld1; - private Int64 _fld2; - private Int64 _fld3; - - static ScalarTernOpTupleTest__DivRemInt64() - { - _clsVar1 = UInt64.MaxValue; - _clsVar2 = -2; - _clsVar3 = -0x100000001; - } - - public ScalarTernOpTupleTest__DivRemInt64() - { - Succeeded = true; - - _fld1 = UInt64.MaxValue; - _fld2 = -2; - _fld3 = -0x100000001; - - _data1 = UInt64.MaxValue; - _data2 = -2; - _data3 = -0x100000001; - } - - public bool IsSupported => X86Base.X64.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.X64.DivRem( - 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(X86Base.X64).GetMethod(nameof(X86Base.X64.DivRem), new Type[] { typeof(UInt64), typeof(Int64), typeof(Int64) }) - .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, ((Int64, Int64))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.X64.DivRem( - _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 = X86Base.X64.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemInt64(); - var result = X86Base.X64.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.X64.DivRem(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, Int64 op2, Int64 op3, (Int64, Int64) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - long expectedQuotient = 0xFFFFFFFF; long expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base.X64)}.{nameof(X86Base.X64.DivRem)}<(Int64, Int64)>(UInt64, Int64, Int64): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs deleted file mode 100644 index 9a974646afed8..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/DivRem.UInt64.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base.X64 -{ - public static partial class Program - { - [Fact] - public static void DivRemUInt64Tuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemUInt64(); - - 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 ScalarTernOpTupleTest__DivRemUInt64 - { - private struct TestStruct - { - public UInt64 _fld1; - public UInt64 _fld2; - public UInt64 _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = 1; - testStruct._fld2 = 1; - testStruct._fld3 = 0x8000000000000000; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemUInt64 testClass) - { - var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, 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 ScalarTernOpTupleTest__DivRemUInt64() - { - _clsVar1 = 1; - _clsVar2 = 1; - _clsVar3 = 0x8000000000000000; - } - - public ScalarTernOpTupleTest__DivRemUInt64() - { - Succeeded = true; - - _fld1 = 1; - _fld2 = 1; - _fld3 = 0x8000000000000000; - - _data1 = 1; - _data2 = 1; - _data3 = 0x8000000000000000; - } - - public bool IsSupported => X86Base.X64.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.X64.DivRem( - 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(X86Base.X64).GetMethod(nameof(X86Base.X64.DivRem), 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)), - Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) - }); - - ValidateResult(_data1, _data2, _data3, ((UInt64, UInt64))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.X64.DivRem( - _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 = X86Base.X64.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemUInt64(); - var result = X86Base.X64.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.X64.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.X64.DivRem(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 op3, (UInt64, UInt64) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - ulong expectedQuotient = 2; ulong expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base.X64)}.{nameof(X86Base.X64.DivRem)}<(UInt64, UInt64)>(UInt64, UInt64, UInt64): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index a8eb433b7dddb..4edd3d923fccd 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -12,8 +12,6 @@ - - diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index c2720a0d03708..fd8a772bfd8c1 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -12,8 +12,6 @@ True - - diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs deleted file mode 100644 index bbf02c95b24a7..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.Int32.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base -{ - public static partial class Program - { - [Fact] - public static void DivRemInt32Tuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemInt32(); - - 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 ScalarTernOpTupleTest__DivRemInt32 - { - private struct TestStruct - { - public UInt32 _fld1; - public Int32 _fld2; - public Int32 _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = UInt32.MaxValue; - testStruct._fld2 = -2; - testStruct._fld3 = -0x10001; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemInt32 testClass) - { - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, result); - } - } - - private static UInt32 _data1; - private static Int32 _data2; - private static Int32 _data3; - - private static UInt32 _clsVar1; - private static Int32 _clsVar2; - private static Int32 _clsVar3; - - private UInt32 _fld1; - private Int32 _fld2; - private Int32 _fld3; - - static ScalarTernOpTupleTest__DivRemInt32() - { - _clsVar1 = UInt32.MaxValue; - _clsVar2 = -2; - _clsVar3 = -0x10001; - } - - public ScalarTernOpTupleTest__DivRemInt32() - { - Succeeded = true; - - _fld1 = UInt32.MaxValue; - _fld2 = -2; - _fld3 = -0x10001; - - _data1 = UInt32.MaxValue; - _data2 = -2; - _data3 = -0x10001; - } - - public bool IsSupported => X86Base.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.DivRem( - 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(UInt32), typeof(Int32), typeof(Int32) }) - .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, ((Int32, Int32))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.DivRem( - _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 = X86Base.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemInt32(); - var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.DivRem(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, Int32 op2, Int32 op3, (Int32, Int32) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - int expectedQuotient = 0xFFFF; int expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(Int32, Int32)>(UInt32, Int32, Int32): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs deleted file mode 100644 index 3ff1529d566c9..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.UInt32.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base -{ - public static partial class Program - { - [Fact] - public static void DivRemUInt32Tuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemUInt32(); - - 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 ScalarTernOpTupleTest__DivRemUInt32 - { - private struct TestStruct - { - public UInt32 _fld1; - public UInt32 _fld2; - public UInt32 _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = 1; - testStruct._fld2 = 1; - testStruct._fld3 = 0x80000000; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemUInt32 testClass) - { - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, 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 ScalarTernOpTupleTest__DivRemUInt32() - { - _clsVar1 = 1; - _clsVar2 = 1; - _clsVar3 = 0x80000000; - } - - public ScalarTernOpTupleTest__DivRemUInt32() - { - Succeeded = true; - - _fld1 = 1; - _fld2 = 1; - _fld3 = 0x80000000; - - _data1 = 1; - _data2 = 1; - _data3 = 0x80000000; - } - - public bool IsSupported => X86Base.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.DivRem( - 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(X86Base).GetMethod(nameof(X86Base.DivRem), 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)), - Unsafe.ReadUnaligned(ref Unsafe.As(ref _data3)) - }); - - ValidateResult(_data1, _data2, _data3, ((UInt32, UInt32))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.DivRem( - _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 = X86Base.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemUInt32(); - var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.DivRem(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 op3, (UInt32, UInt32) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - uint expectedQuotient = 2; uint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(UInt32, UInt32)>(UInt32, UInt32, UInt32): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs deleted file mode 100644 index ab234c1e57c76..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nint.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base -{ - public static partial class Program - { - [Fact] - public static void DivRemnintTuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemnint(); - - 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 ScalarTernOpTupleTest__DivRemnint - { - private struct TestStruct - { - public nuint _fld1; - public nint _fld2; - public nint _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = nuint.MaxValue; - testStruct._fld2 = -2; - testStruct._fld3 = -((nint)1 << (IntPtr.Size * 4)) - 1; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemnint testClass) - { - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, result); - } - } - - private static nuint _data1; - private static nint _data2; - private static nint _data3; - - private static nuint _clsVar1; - private static nint _clsVar2; - private static nint _clsVar3; - - private nuint _fld1; - private nint _fld2; - private nint _fld3; - - static ScalarTernOpTupleTest__DivRemnint() - { - _clsVar1 = nuint.MaxValue; - _clsVar2 = -2; - _clsVar3 = -((nint)1 << (IntPtr.Size * 4)) - 1; - } - - public ScalarTernOpTupleTest__DivRemnint() - { - Succeeded = true; - - _fld1 = nuint.MaxValue; - _fld2 = -2; - _fld3 = -((nint)1 << (IntPtr.Size * 4)) - 1; - - _data1 = nuint.MaxValue; - _data2 = -2; - _data3 = -((nint)1 << (IntPtr.Size * 4)) - 1; - } - - public bool IsSupported => X86Base.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.DivRem( - 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(nuint), typeof(nint), typeof(nint) }) - .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, ((nint, nint))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.DivRem( - _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 = X86Base.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemnint(); - var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.DivRem(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(nuint op1, nint op2, nint op3, (nint, nint) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - nint expectedQuotient = ((nint)1 << (IntPtr.Size * 4)) - 1; nint expectedReminder = -2; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(nint, nint)>(nuint, nint, nint): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs deleted file mode 100644 index 966bf95660950..0000000000000 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.nuint.Tuple3Op.cs +++ /dev/null @@ -1,259 +0,0 @@ -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. - -/****************************************************************************** - * 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; -using Xunit; - -[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] -namespace JIT.HardwareIntrinsics.X86._X86Base -{ - public static partial class Program - { - [Fact] - public static void DivRemnuintTuple3Op() - { - var test = new ScalarTernOpTupleTest__DivRemnuint(); - - 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 ScalarTernOpTupleTest__DivRemnuint - { - private struct TestStruct - { - public nuint _fld1; - public nuint _fld2; - public nuint _fld3; - - public static TestStruct Create() - { - var testStruct = new TestStruct(); - - testStruct._fld1 = 1; - testStruct._fld2 = 1; - testStruct._fld3 = (nuint)nint.MinValue; - - return testStruct; - } - - public void RunStructFldScenario(ScalarTernOpTupleTest__DivRemnuint testClass) - { - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - testClass.ValidateResult(_fld1, _fld2, _fld3, result); - } - } - - private static nuint _data1; - private static nuint _data2; - private static nuint _data3; - - private static nuint _clsVar1; - private static nuint _clsVar2; - private static nuint _clsVar3; - - private nuint _fld1; - private nuint _fld2; - private nuint _fld3; - - static ScalarTernOpTupleTest__DivRemnuint() - { - _clsVar1 = 1; - _clsVar2 = 1; - _clsVar3 = (nuint)nint.MinValue; - } - - public ScalarTernOpTupleTest__DivRemnuint() - { - Succeeded = true; - - _fld1 = 1; - _fld2 = 1; - _fld3 = (nuint)nint.MinValue; - - _data1 = 1; - _data2 = 1; - _data3 = (nuint)nint.MinValue; - } - - public bool IsSupported => X86Base.IsSupported; - - public bool Succeeded { get; set; } - - public void RunBasicScenario_UnsafeRead() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunBasicScenario_UnsafeRead)); - - var result = X86Base.DivRem( - 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(X86Base).GetMethod(nameof(X86Base.DivRem), new Type[] { typeof(nuint), typeof(nuint), typeof(nuint) }) - .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, ((nuint, nuint))result); - } - - public void RunClsVarScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClsVarScenario)); - - var result = X86Base.DivRem( - _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 = X86Base.DivRem(data1, data2, data3); - - ValidateResult(data1, data2, data3, result); - } - - public void RunClassLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassLclFldScenario)); - - var test = new ScalarTernOpTupleTest__DivRemnuint(); - var result = X86Base.DivRem(test._fld1, test._fld2, test._fld3); - - ValidateResult(test._fld1, test._fld2, test._fld3, result); - } - - public void RunClassFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunClassFldScenario)); - - var result = X86Base.DivRem(_fld1, _fld2, _fld3); - ValidateResult(_fld1, _fld2, _fld3, result); - } - - public void RunStructLclFldScenario() - { - TestLibrary.TestFramework.BeginScenario(nameof(RunStructLclFldScenario)); - - var test = TestStruct.Create(); - var result = X86Base.DivRem(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(nuint op1, nuint op2, nuint op3, (nuint, nuint) result, [CallerMemberName] string method = "") - { - (var ret1, var ret2) = result; - var isUnexpectedResult = false; - - nuint expectedQuotient = 2; nuint expectedReminder = 1; isUnexpectedResult = (expectedQuotient != ret1) || (expectedReminder != ret2); - - if (isUnexpectedResult) - { - TestLibrary.TestFramework.LogInformation($"{nameof(X86Base)}.{nameof(X86Base.DivRem)}<(nuint, nuint)>(nuint, nuint, nuint): DivRem failed:"); - TestLibrary.TestFramework.LogInformation($" op1: {op1}"); - TestLibrary.TestFramework.LogInformation($" op2: {op2}"); - TestLibrary.TestFramework.LogInformation($" op3: {op3}"); - TestLibrary.TestFramework.LogInformation($" result1: {ret1}"); - TestLibrary.TestFramework.LogInformation($" result2: {ret2}"); - TestLibrary.TestFramework.LogInformation(string.Empty); - - Succeeded = false; - } - } - } -} diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index fd05cd48f1afa..b4db08053dcfc 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -11,10 +11,6 @@ - - - - diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 1dc655eec0673..13f9d7ab90504 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -11,10 +11,6 @@ True - - - - From 8d67890c553735645b12d638a61285e3f6aa6429 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 11 Jan 2023 18:52:55 -0800 Subject: [PATCH 42/71] Disable for llvm-fullaot --- src/tests/issues.targets | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 8a2f9879fafd1..fd820089f8c95 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1369,13 +1369,6 @@ https://github.com/dotnet/runtime/issues/54185 - - https://github.com/dotnet/runtime/pull/66551#issuecomment-1066120794 - - - https://github.com/dotnet/runtime/pull/66551#issuecomment-1066120794 - - Mono does not define out of range fp to int conversions @@ -2748,6 +2741,13 @@ https://github.com/dotnet/runtime/issues/75767 + + https://github.com/dotnet/runtime/issues/75767 + + + https://github.com/dotnet/runtime/issues/75767 + + From 0d85848902a08c90b5d50132bb634694a29d74a7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 12 Jan 2023 10:47:22 -0800 Subject: [PATCH 43/71] Also continue disabling for mono --- src/tests/issues.targets | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index fd820089f8c95..374532d739b34 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1369,6 +1369,12 @@ https://github.com/dotnet/runtime/issues/54185 + + https://github.com/dotnet/runtime/issues/75767 + + + https://github.com/dotnet/runtime/issues/75767 + Mono does not define out of range fp to int conversions From 18c978788c9e2e5933df5b2c51a47985da601f5a Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 12 Jan 2023 15:07:43 -0800 Subject: [PATCH 44/71] Disable the test in a different group --- src/tests/issues.targets | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index 115139bca7e82..854da18b84b19 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2756,13 +2756,6 @@ https://github.com/dotnet/runtime/issues/75767 - - https://github.com/dotnet/runtime/issues/75767 - - - https://github.com/dotnet/runtime/issues/75767 - - @@ -3123,6 +3116,12 @@ https://github.com/dotnet/runtime/issues/73454;https://github.com/dotnet/runtime/pull/61707#issuecomment-973122341 + + https://github.com/dotnet/runtime/issues/75767 + + + https://github.com/dotnet/runtime/issues/75767 + needs triage From 1b0e670a4b0b520e8751ee6581e542d95caf5de2 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 13 Jan 2023 11:52:23 -0800 Subject: [PATCH 45/71] fix merge conflict --- src/coreclr/jit/hwintrinsicxarch.cpp | 85 +++++++++++++++++----------- 1 file changed, 51 insertions(+), 34 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 0e41d1f5cc1f8..92cc48c2f7ec7 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -498,9 +498,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, var_types retType, unsigned simdSize) { - case InstructionSet_X86Base: - case InstructionSet_X86Base_X64: - return impX86BaseIntrinsic(intrinsic, method, sig, simdBaseJitType); GenTree* retNode = nullptr; GenTree* op1 = nullptr; GenTree* op2 = nullptr; @@ -2328,31 +2325,6 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } - default: - { - return nullptr; - } - } - - return retNode; -} - -GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig, - CorInfoType simdBaseJitType) -{ - GenTree* retNode = nullptr; - GenTree* op1 = nullptr; - GenTree* op2 = nullptr; - GenTree* op3 = nullptr; - GenTree* op4 = nullptr; - - var_types retType = JITtype2varType(sig->retType); - - switch (intrinsic) - { - case NI_X86Base_Pause: case NI_X86Serialize_Serialize: { @@ -2363,9 +2335,8 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; } - - case NI_X86Base_DivRem: - case NI_X86Base_X64_DivRem: + case InstructionSet_X86Base: + case InstructionSet_X86Base_X64: { assert(sig->numArgs == 3); assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); @@ -2386,7 +2357,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_SSE_CompareScalarGreaterThan: + case NI_SSE_CompareScalarGreaterThan: case NI_SSE_CompareScalarGreaterThanOrEqual: case NI_SSE_CompareScalarNotGreaterThan: case NI_SSE_CompareScalarNotGreaterThanOrEqual: @@ -2420,7 +2391,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, { GenTree* clonedOp1 = nullptr; op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL, - nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan")); + nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan")); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE_MoveScalar, simdBaseJitType, @@ -2480,7 +2451,7 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, { GenTree* clonedOp1 = nullptr; op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL, - nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan")); + nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan")); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE2_MoveScalar, simdBaseJitType, @@ -2614,4 +2585,50 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, return retNode; } + +GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, + CORINFO_METHOD_HANDLE method, + CORINFO_SIG_INFO* sig, + CorInfoType simdBaseJitType) +{ + GenTree* retNode = nullptr; + GenTree* op1 = nullptr; + GenTree* op2 = nullptr; + GenTree* op3 = nullptr; + GenTree* op4 = nullptr; + + var_types retType = JITtype2varType(sig->retType); + + switch (intrinsic) + { + + + + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: + { + assert(sig->numArgs == 3); + assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); + assert(retType == TYP_STRUCT); + assert(simdBaseJitType != CORINFO_TYPE_UNDEF); + + op3 = impPopStack().val; + op2 = impPopStack().val; + op1 = impPopStack().val; + + GenTreeHWIntrinsic* divRemIntrinsic = gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic); + + // Store the type from signature into SIMD base type for convenience + divRemIntrinsic->SetSimdBaseJitType(simdBaseJitType); + + retNode = impAssignMultiRegTypeToVar(divRemIntrinsic, + sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); + break; + } + + + } + + return retNode; +} #endif // FEATURE_HW_INTRINSICS From 7631033b58447f066ea95b1a8654b810d13c2e26 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 13 Jan 2023 13:28:40 -0800 Subject: [PATCH 46/71] format --- src/coreclr/jit/hwintrinsicxarch.cpp | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 92cc48c2f7ec7..58d9785b0e4a6 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2357,7 +2357,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, break; } - case NI_SSE_CompareScalarGreaterThan: + case NI_SSE_CompareScalarGreaterThan: case NI_SSE_CompareScalarGreaterThanOrEqual: case NI_SSE_CompareScalarNotGreaterThan: case NI_SSE_CompareScalarNotGreaterThanOrEqual: @@ -2391,7 +2391,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { GenTree* clonedOp1 = nullptr; op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL, - nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan")); + nullptr DEBUGARG("Clone op1 for Sse.CompareScalarGreaterThan")); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE_MoveScalar, simdBaseJitType, @@ -2451,7 +2451,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, { GenTree* clonedOp1 = nullptr; op1 = impCloneExpr(op1, &clonedOp1, NO_CLASS_HANDLE, CHECK_SPILL_ALL, - nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan")); + nullptr DEBUGARG("Clone op1 for Sse2.CompareScalarGreaterThan")); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, op2, op1, intrinsic, simdBaseJitType, simdSize); retNode = gtNewSimdHWIntrinsicNode(TYP_SIMD16, clonedOp1, retNode, NI_SSE2_MoveScalar, simdBaseJitType, @@ -2602,8 +2602,6 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, switch (intrinsic) { - - case NI_X86Base_DivRem: case NI_X86Base_X64_DivRem: { @@ -2625,8 +2623,6 @@ GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); break; } - - } return retNode; From c0be00add8966d93555e1b18303ae23f0ef47f59 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 13 Jan 2023 22:56:14 -0800 Subject: [PATCH 47/71] fix another merge conflict error --- src/coreclr/jit/compiler.h | 5 +-- src/coreclr/jit/hwintrinsicxarch.cpp | 47 ++-------------------------- 2 files changed, 4 insertions(+), 48 deletions(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index d124b206ee647..f71b5d4f29078 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3857,10 +3857,7 @@ class Compiler GenTree* addRangeCheckIfNeeded( NamedIntrinsic intrinsic, GenTree* immOp, bool mustExpand, int immLowerBound, int immUpperBound); GenTree* addRangeCheckForHWIntrinsic(GenTree* immOp, int immLowerBound, int immUpperBound); - GenTree* impX86BaseIntrinsic(NamedIntrinsic intrinsic, - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig, - CorInfoType simdBaseJitType); + #endif // FEATURE_HW_INTRINSICS GenTree* impArrayAccessIntrinsic(CORINFO_CLASS_HANDLE clsHnd, CORINFO_SIG_INFO* sig, diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 58d9785b0e4a6..b428e2af9a68d 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -2335,8 +2335,9 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; } - case InstructionSet_X86Base: - case InstructionSet_X86Base_X64: + + case NI_X86Base_DivRem: + case NI_X86Base_X64_DivRem: { assert(sig->numArgs == 3); assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); @@ -2585,46 +2586,4 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, return retNode; } - -GenTree* Compiler::impX86BaseIntrinsic(NamedIntrinsic intrinsic, - CORINFO_METHOD_HANDLE method, - CORINFO_SIG_INFO* sig, - CorInfoType simdBaseJitType) -{ - GenTree* retNode = nullptr; - GenTree* op1 = nullptr; - GenTree* op2 = nullptr; - GenTree* op3 = nullptr; - GenTree* op4 = nullptr; - - var_types retType = JITtype2varType(sig->retType); - - switch (intrinsic) - { - - case NI_X86Base_DivRem: - case NI_X86Base_X64_DivRem: - { - assert(sig->numArgs == 3); - assert(HWIntrinsicInfo::IsMultiReg(intrinsic)); - assert(retType == TYP_STRUCT); - assert(simdBaseJitType != CORINFO_TYPE_UNDEF); - - op3 = impPopStack().val; - op2 = impPopStack().val; - op1 = impPopStack().val; - - GenTreeHWIntrinsic* divRemIntrinsic = gtNewScalarHWIntrinsicNode(retType, op1, op2, op3, intrinsic); - - // Store the type from signature into SIMD base type for convenience - divRemIntrinsic->SetSimdBaseJitType(simdBaseJitType); - - retNode = impAssignMultiRegTypeToVar(divRemIntrinsic, - sig->retTypeSigClass DEBUGARG(CorInfoCallConvExtension::Managed)); - break; - } - } - - return retNode; -} #endif // FEATURE_HW_INTRINSICS From b29e1b466ec15b52fc237e926686cec4b664a02f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 17 Jan 2023 11:56:54 -0800 Subject: [PATCH 48/71] misc changes from review --- src/coreclr/jit/hwintrinsicxarch.cpp | 6 +++--- src/coreclr/jit/lower.cpp | 19 +++++++++++-------- .../System/Runtime/Intrinsics/X86/X86Base.cs | 12 ++++++------ 3 files changed, 20 insertions(+), 17 deletions(-) diff --git a/src/coreclr/jit/hwintrinsicxarch.cpp b/src/coreclr/jit/hwintrinsicxarch.cpp index 1e9b4961cdb7e..22303b4ad12e4 100644 --- a/src/coreclr/jit/hwintrinsicxarch.cpp +++ b/src/coreclr/jit/hwintrinsicxarch.cpp @@ -512,7 +512,7 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, return nullptr; } - var_types simdBaseType = JitType2PreciseVarType(simdBaseJitType); + var_types simdBaseType = TYP_UNKNOWN; if (simdSize != 0) { simdBaseType = JitType2PreciseVarType(simdBaseJitType); @@ -2358,8 +2358,8 @@ GenTree* Compiler::impSpecialIntrinsic(NamedIntrinsic intrinsic, case NI_X86Serialize_Serialize: { assert(sig->numArgs == 0); - assert(retType == TYP_VOID); - assert(simdBaseJitType == CORINFO_TYPE_UNDEF); + assert(JITtype2varType(sig->retType) == TYP_VOID); + assert(simdSize == 0); retNode = gtNewScalarHWIntrinsicNode(TYP_VOID, intrinsic); break; diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index b02d94d8e90e5..334bff25f5491 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6926,15 +6926,18 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* } } } -#ifdef TARGET_XARCH - // For local stores on XARCH we can't handle another lclVar source. - // If the source was another lclVar similarly promoted, we would have broken it into multiple stores. - if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && - lclNode->gtGetOp1()->OperIs(GT_LCL_VAR)) + else { - canEnregister = false; - } + canEnregister = varTypeIsSIMD(lclNode); +#ifdef TARGET_XARCH + // For local stores on XARCH we only handle mismatched src/dest register count for calls of SIMD type. + // If the source was another lclVar similarly promoted, we would have broken it into multiple stores. + if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && !lclNode->Data()->OperIs(GT_CALL)) + { + canEnregister = false; + } #endif // TARGET_XARCH + } if (canEnregister) { @@ -6943,7 +6946,7 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* else { lclNode->ClearMultiReg(); - if (varDsc->lvPromoted && !varDsc->lvDoNotEnregister) + if (!varDsc->lvDoNotEnregister) { comp->lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::BlockOp)); } diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs index e07b5979ab463..2a0b3e13919a2 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -92,12 +92,6 @@ public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, return (cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]); } - /// - /// void _mm_pause (void); - /// PAUSE - /// - public static void Pause() => Pause(); - /// /// unsigned _udiv64(unsigned __int64 dividend, unsigned divisor, unsigned* remainder) /// DIV reg/m32 @@ -119,5 +113,11 @@ public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, /// IDIV reg/m /// public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) => DivRem(lower, upper, divisor); + + /// + /// void _mm_pause (void); + /// PAUSE + /// + public static void Pause() => Pause(); } } From 82c38a391fae0b880524a35fc1a30c792b444578 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 18 Jan 2023 06:36:50 -0800 Subject: [PATCH 49/71] fix the replay errors --- src/coreclr/jit/lower.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 334bff25f5491..f9b834b667ab2 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6900,6 +6900,7 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc) { bool canEnregister = false; + #if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) LclVarDsc* varDsc = comp->lvaGetDesc(lclNode->GetLclNum()); if ((comp->lvaEnregMultiRegVars) && varDsc->lvPromoted) @@ -6926,18 +6927,18 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* } } } +#ifdef TARGET_XARCH else { - canEnregister = varTypeIsSIMD(lclNode); -#ifdef TARGET_XARCH // For local stores on XARCH we only handle mismatched src/dest register count for calls of SIMD type. // If the source was another lclVar similarly promoted, we would have broken it into multiple stores. if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && !lclNode->Data()->OperIs(GT_CALL)) { canEnregister = false; } -#endif // TARGET_XARCH } +#endif // TARGET_XARCH + if (canEnregister) { From 61fabe25eb1e889804c17d75908d9df573778cb4 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 18 Jan 2023 11:35:53 -0800 Subject: [PATCH 50/71] jit format --- src/coreclr/jit/lower.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index f9b834b667ab2..6c245efcf0f2f 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -6939,7 +6939,6 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* } #endif // TARGET_XARCH - if (canEnregister) { lclNode->SetMultiReg(); From eea804c1b6149a31d2e6ed427ceb78705bd3831b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 18 Jan 2023 11:59:01 -0800 Subject: [PATCH 51/71] Add exclude list in mono/llvmfullaot --- src/tests/issues.targets | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index d2d6fa81ffc35..574f4c9c4658d 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -2813,6 +2813,12 @@ expected failure: unsupported type with ByRefLike parameters currently fails at AOT compile time, not runtime + + https://github.com/dotnet/runtime/issues/75767 + + + https://github.com/dotnet/runtime/issues/75767 + https://github.com/dotnet/runtime/issues/70490 From ebe8781ae11a2f0baf3fbb99c331f8b1ca0e6b3b Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Jan 2023 00:20:29 -0800 Subject: [PATCH 52/71] Review feedback and fix bug in CheckMultiRegLclVar --- src/coreclr/jit/importer.cpp | 2 +- src/coreclr/jit/lower.cpp | 42 ++++++---- src/coreclr/jit/lowerxarch.cpp | 2 +- src/coreclr/jit/lsra.h | 2 +- .../System.Private.CoreLib/src/System/Math.cs | 82 ------------------- 5 files changed, 27 insertions(+), 103 deletions(-) diff --git a/src/coreclr/jit/importer.cpp b/src/coreclr/jit/importer.cpp index 62fb6885cb269..44a59d628230b 100644 --- a/src/coreclr/jit/importer.cpp +++ b/src/coreclr/jit/importer.cpp @@ -10855,7 +10855,7 @@ GenTree* Compiler::impAssignMultiRegTypeToVar(GenTree* op, LclVarDsc* varDsc = lvaGetDesc(tmpNum); - // The following is to exclude the fields of the local to have SSA. + // Set "lvIsMultiRegRet" to block promotion under "!lvaEnregMultiRegVars". varDsc->lvIsMultiRegRet = true; GenTreeLclVar* ret = gtNewLclvNode(tmpNum, varDsc->lvType); diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 6c245efcf0f2f..9a27b83fc9157 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3538,6 +3538,7 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) { retTypeDesc = src->AsCall()->GetReturnTypeDesc(); } + CheckMultiRegLclVar(lclStore->AsLclVar(), retTypeDesc); } @@ -6899,22 +6900,29 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) // bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc) { - bool canEnregister = false; + bool canEnregisterAsMultiReg = false; + bool canEnregisterAsSingleReg = false; #if FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) LclVarDsc* varDsc = comp->lvaGetDesc(lclNode->GetLclNum()); + if (varDsc->lvDoNotEnregister) + { + assert(!lclNode->IsMultiReg()); + return false; + } + if ((comp->lvaEnregMultiRegVars) && varDsc->lvPromoted) { // We can enregister if we have a promoted struct and all the fields' types match the ABI requirements. // Note that we don't promote structs with explicit layout, so we don't need to check field offsets, and // if we have multiple types packed into a single register, we won't have matching reg and field counts, // so we can tolerate mismatches of integer size. - if (varDsc->lvPromoted && (comp->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_INDEPENDENT)) + if (comp->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_INDEPENDENT) { // If we have no retTypeDesc, we only care that it is independently promoted. if (retTypeDesc == nullptr) { - canEnregister = true; + canEnregisterAsMultiReg = true; } else { @@ -6922,38 +6930,36 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* if (regCount == varDsc->lvFieldCnt) { - canEnregister = true; + canEnregisterAsMultiReg = true; } } } } -#ifdef TARGET_XARCH else { - // For local stores on XARCH we only handle mismatched src/dest register count for calls of SIMD type. - // If the source was another lclVar similarly promoted, we would have broken it into multiple stores. + canEnregisterAsSingleReg = varTypeIsSIMD(lclNode); +#ifdef TARGET_XARCH if (lclNode->OperIs(GT_STORE_LCL_VAR) && varTypeIsStruct(lclNode->Data()) && !lclNode->Data()->OperIs(GT_CALL)) { - canEnregister = false; + canEnregisterAsSingleReg = false; } - } #endif // TARGET_XARCH + } - if (canEnregister) + if (canEnregisterAsSingleReg || canEnregisterAsMultiReg) { - lclNode->SetMultiReg(); + if (canEnregisterAsMultiReg) + { + lclNode->SetMultiReg(); + } } else { - lclNode->ClearMultiReg(); - if (!varDsc->lvDoNotEnregister) - { - comp->lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::BlockOp)); - } + comp->lvaSetVarDoNotEnregister(lclNode->GetLclNum() DEBUGARG(DoNotEnregisterReason::BlockOp)); } -#endif +#endif // FEATURE_MULTIREG_RET || defined(FEATURE_HW_INTRINSICS) - return canEnregister; + return canEnregisterAsSingleReg || canEnregisterAsMultiReg; } //------------------------------------------------------------------------ diff --git a/src/coreclr/jit/lowerxarch.cpp b/src/coreclr/jit/lowerxarch.cpp index 618c617355c92..b57bcd7d26da7 100644 --- a/src/coreclr/jit/lowerxarch.cpp +++ b/src/coreclr/jit/lowerxarch.cpp @@ -7306,7 +7306,7 @@ void Lowering::ContainCheckHWIntrinsic(GenTreeHWIntrinsic* node) } else if (supportsRegOptional) { - op3->SetRegOptional(); + MakeSrcRegOptional(node, op3); } break; } diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index d0a0ca4cf83ce..955a60e2b9d36 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -2254,7 +2254,7 @@ class RefPosition // Used by RefTypeDef/Use positions of a multi-reg call node. // Indicates the position of the register that this ref position refers to. - // The max bits needed is based on max value of MAX_RET_REG_COUNT value + // The max bits needed is based on max value of MAX_MULTIREG_COUNT value // across all targets and that happened to be 4 on Arm. Hence index value // would be 0..MAX_MULTIREG_COUNT-1. unsigned char multiRegIdx : 2; diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index 917b0f56723d0..c73ad69171e7d 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -317,15 +317,6 @@ public static int DivRem(int a, int b, out int result) // Restore to using % and / when the JIT is able to eliminate one of the idivs. // In the meantime, a * and - is measurably faster than an extra /. - // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - (int quotient, result) = X86Base.DivRem((uint)a, a >> 31, b); - return quotient; - } -#endif - int div = a / b; result = a - (div * b); return div; @@ -334,13 +325,6 @@ public static int DivRem(int a, int b, out int result) public static long DivRem(long a, long b, out long result) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.X64.IsSupported) - { - (long quotient, result) = X86Base.X64.DivRem((ulong)a, a >> 63, b); - return quotient; - } -#endif long div = a / b; result = a - (div * b); @@ -357,14 +341,6 @@ public static long DivRem(long a, long b, out long result) public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - int dividend = left; - (int q, int r) = X86Base.DivRem((uint)dividend, dividend >> 31, right); - return ((sbyte)q, (sbyte)r); - } -#endif sbyte quotient = (sbyte)(left / right); return (quotient, (sbyte)(left - (quotient * right))); @@ -379,13 +355,6 @@ public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - (uint q, uint r) = X86Base.DivRem(left, 0u, right); - return ((byte)q, (byte)r); - } -#endif byte quotient = (byte)(left / right); return (quotient, (byte)(left - (quotient * right))); @@ -400,14 +369,6 @@ public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) public static (short Quotient, short Remainder) DivRem(short left, short right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - int dividend = left; - (int q, int r) = X86Base.DivRem((uint)dividend, dividend >> 31, right); - return ((short)q, (short)r); - } -#endif short quotient = (short)(left / right); return (quotient, (short)(left - (quotient * right))); @@ -423,13 +384,6 @@ public static (short Quotient, short Remainder) DivRem(short left, short right) public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - (uint q, uint r) = X86Base.DivRem(left, 0u, right); - return ((ushort)q, (ushort)r); - } -#endif ushort quotient = (ushort)(left / right); return (quotient, (ushort)(left - (quotient * right))); @@ -444,12 +398,6 @@ public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort rig public static (int Quotient, int Remainder) DivRem(int left, int right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - return X86Base.DivRem((uint)left, left >> 31, right); - } -#endif int quotient = left / right; return (quotient, left - (quotient * right)); @@ -465,12 +413,6 @@ public static (int Quotient, int Remainder) DivRem(int left, int right) public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - return X86Base.DivRem(left, 0u, right); - } -#endif uint quotient = left / right; return (quotient, left - (quotient * right)); @@ -485,12 +427,6 @@ public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) public static (long Quotient, long Remainder) DivRem(long left, long right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.X64.IsSupported) - { - return X86Base.X64.DivRem((ulong)left, left >> 63, right); - } -#endif long quotient = left / right; return (quotient, left - (quotient * right)); @@ -506,12 +442,6 @@ public static (long Quotient, long Remainder) DivRem(long left, long right) public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.X64.IsSupported) - { - return X86Base.X64.DivRem(left, 0ul, right); - } -#endif ulong quotient = left / right; return (quotient, left - (quotient * right)); @@ -526,12 +456,6 @@ public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - return X86Base.DivRem((nuint)left, left >> (IntPtr.Size * 8 - 1), right); - } -#endif // !MONO nint quotient = left / right; return (quotient, left - (quotient * right)); @@ -547,12 +471,6 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { // TODO: implement DivRem intrinsic for Mono -#if !MONO - if (X86Base.IsSupported) - { - return X86Base.DivRem(left, (nuint)0, right); - } -#endif nuint quotient = left / right; return (quotient, left - (quotient * right)); From 9dc8522d912296f9426a334e080848ce01613fbb Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Jan 2023 11:41:43 -0800 Subject: [PATCH 53/71] Pass registerCount --- src/coreclr/jit/lower.cpp | 32 +++++--------------------------- src/coreclr/jit/lower.h | 2 +- 2 files changed, 6 insertions(+), 28 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index 9a27b83fc9157..f5ad27cdf6e8b 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3448,7 +3448,7 @@ void Lowering::LowerRet(GenTreeUnOp* ret) #if FEATURE_MULTIREG_RET if (comp->compMethodReturnsMultiRegRetType() && retVal->OperIs(GT_LCL_VAR)) { - CheckMultiRegLclVar(retVal->AsLclVar(), &comp->compRetTypeDesc); + CheckMultiRegLclVar(retVal->AsLclVar(), retVal->GetMultiRegCount(comp)); } #endif // FEATURE_MULTIREG_RET #ifdef DEBUG @@ -3533,13 +3533,7 @@ void Lowering::LowerStoreLocCommon(GenTreeLclVarCommon* lclStore) if (srcIsMultiReg) { - const ReturnTypeDesc* retTypeDesc = nullptr; - if (src->OperIs(GT_CALL)) - { - retTypeDesc = src->AsCall()->GetReturnTypeDesc(); - } - - CheckMultiRegLclVar(lclStore->AsLclVar(), retTypeDesc); + CheckMultiRegLclVar(lclStore->AsLclVar(), src->GetMultiRegCount(comp)); } const var_types lclRegType = varDsc->GetRegisterType(lclStore); @@ -6890,15 +6884,9 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) // // Arguments: // lclNode - the GT_LCL_VAR or GT_STORE_LCL_VAR node. -// retTypeDesc - a return type descriptor either for a call source of a store of -// the local, or for the GT_RETURN consumer of the local. +// registerCount - register count of source of a store. // -// Notes: -// If retTypeDesc is non-null, this method will check that the fields are compatible. -// Otherwise, it will only check that the lclVar is independently promoted -// (i.e. it is marked lvPromoted and not lvDoNotEnregister). -// -bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc) +bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, int registerCount) { bool canEnregisterAsMultiReg = false; bool canEnregisterAsSingleReg = false; @@ -6919,20 +6907,10 @@ bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* // so we can tolerate mismatches of integer size. if (comp->lvaGetPromotionType(varDsc) == Compiler::PROMOTION_TYPE_INDEPENDENT) { - // If we have no retTypeDesc, we only care that it is independently promoted. - if (retTypeDesc == nullptr) + if (registerCount == varDsc->lvFieldCnt) { canEnregisterAsMultiReg = true; } - else - { - unsigned regCount = retTypeDesc->GetReturnRegCount(); - - if (regCount == varDsc->lvFieldCnt) - { - canEnregisterAsMultiReg = true; - } - } } } else diff --git a/src/coreclr/jit/lower.h b/src/coreclr/jit/lower.h index 23aef6fbaea2e..e1e30f8a675af 100644 --- a/src/coreclr/jit/lower.h +++ b/src/coreclr/jit/lower.h @@ -339,7 +339,7 @@ class Lowering final : public Phase #endif void WidenSIMD12IfNecessary(GenTreeLclVarCommon* node); - bool CheckMultiRegLclVar(GenTreeLclVar* lclNode, const ReturnTypeDesc* retTypeDesc); + bool CheckMultiRegLclVar(GenTreeLclVar* lclNode, int registerCount); void LowerStoreLoc(GenTreeLclVarCommon* tree); GenTree* LowerArrElem(GenTreeArrElem* arrElem); void LowerRotate(GenTree* tree); From 0093b7973c1df2b747a8d2b35bb57d00c2194ded Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 20 Jan 2023 12:38:08 -0800 Subject: [PATCH 54/71] review feedback --- src/coreclr/jit/lower.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/lower.cpp b/src/coreclr/jit/lower.cpp index f5ad27cdf6e8b..ec334f9fc72b5 100644 --- a/src/coreclr/jit/lower.cpp +++ b/src/coreclr/jit/lower.cpp @@ -3448,7 +3448,7 @@ void Lowering::LowerRet(GenTreeUnOp* ret) #if FEATURE_MULTIREG_RET if (comp->compMethodReturnsMultiRegRetType() && retVal->OperIs(GT_LCL_VAR)) { - CheckMultiRegLclVar(retVal->AsLclVar(), retVal->GetMultiRegCount(comp)); + CheckMultiRegLclVar(retVal->AsLclVar(), comp->compRetTypeDesc.GetReturnRegCount()); } #endif // FEATURE_MULTIREG_RET #ifdef DEBUG @@ -6883,8 +6883,8 @@ bool Lowering::NodesAreEquivalentLeaves(GenTree* tree1, GenTree* tree2) // remain a multi-reg. // // Arguments: -// lclNode - the GT_LCL_VAR or GT_STORE_LCL_VAR node. -// registerCount - register count of source of a store. +// lclNode - the GT_LCL_VAR or GT_STORE_LCL_VAR node. +// registerCount - use register count for uses; source register count for stores. // bool Lowering::CheckMultiRegLclVar(GenTreeLclVar* lclNode, int registerCount) { From 82601348a1537754b1fc693690c762873405018f Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 23 Jan 2023 22:52:17 -0800 Subject: [PATCH 55/71] Remove the extra comments --- .../System.Private.CoreLib/src/System/Math.cs | 22 ------------------- 1 file changed, 22 deletions(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Math.cs b/src/libraries/System.Private.CoreLib/src/System/Math.cs index c73ad69171e7d..5c7252bfefffe 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Math.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Math.cs @@ -324,8 +324,6 @@ public static int DivRem(int a, int b, out int result) public static long DivRem(long a, long b, out long result) { - // TODO: implement DivRem intrinsic for Mono - long div = a / b; result = a - (div * b); return div; @@ -340,8 +338,6 @@ public static long DivRem(long a, long b, out long result) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) { - // TODO: implement DivRem intrinsic for Mono - sbyte quotient = (sbyte)(left / right); return (quotient, (sbyte)(left - (quotient * right))); } @@ -354,8 +350,6 @@ public static (sbyte Quotient, sbyte Remainder) DivRem(sbyte left, sbyte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) { - // TODO: implement DivRem intrinsic for Mono - byte quotient = (byte)(left / right); return (quotient, (byte)(left - (quotient * right))); } @@ -368,8 +362,6 @@ public static (byte Quotient, byte Remainder) DivRem(byte left, byte right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (short Quotient, short Remainder) DivRem(short left, short right) { - // TODO: implement DivRem intrinsic for Mono - short quotient = (short)(left / right); return (quotient, (short)(left - (quotient * right))); } @@ -383,8 +375,6 @@ public static (short Quotient, short Remainder) DivRem(short left, short right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort right) { - // TODO: implement DivRem intrinsic for Mono - ushort quotient = (ushort)(left / right); return (quotient, (ushort)(left - (quotient * right))); } @@ -397,8 +387,6 @@ public static (ushort Quotient, ushort Remainder) DivRem(ushort left, ushort rig [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (int Quotient, int Remainder) DivRem(int left, int right) { - // TODO: implement DivRem intrinsic for Mono - int quotient = left / right; return (quotient, left - (quotient * right)); } @@ -412,8 +400,6 @@ public static (int Quotient, int Remainder) DivRem(int left, int right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) { - // TODO: implement DivRem intrinsic for Mono - uint quotient = left / right; return (quotient, left - (quotient * right)); } @@ -426,8 +412,6 @@ public static (uint Quotient, uint Remainder) DivRem(uint left, uint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (long Quotient, long Remainder) DivRem(long left, long right) { - // TODO: implement DivRem intrinsic for Mono - long quotient = left / right; return (quotient, left - (quotient * right)); } @@ -441,8 +425,6 @@ public static (long Quotient, long Remainder) DivRem(long left, long right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) { - // TODO: implement DivRem intrinsic for Mono - ulong quotient = left / right; return (quotient, left - (quotient * right)); } @@ -455,8 +437,6 @@ public static (ulong Quotient, ulong Remainder) DivRem(ulong left, ulong right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) { - // TODO: implement DivRem intrinsic for Mono - nint quotient = left / right; return (quotient, left - (quotient * right)); } @@ -470,8 +450,6 @@ public static (nint Quotient, nint Remainder) DivRem(nint left, nint right) [MethodImpl(MethodImplOptions.AggressiveInlining)] public static (nuint Quotient, nuint Remainder) DivRem(nuint left, nuint right) { - // TODO: implement DivRem intrinsic for Mono - nuint quotient = left / right; return (quotient, left - (quotient * right)); } From 320270a960b63dbf717cf2e59cb5fd419abeebac Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Alexander=20K=C3=B6plinger?= Date: Tue, 24 Jan 2023 16:08:56 +0100 Subject: [PATCH 56/71] Disable tests on mono llvmfullaot runs as well --- .../HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs | 1 + src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs index 230f3249752dc..7539c8c3014c3 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; [assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMFULLAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base.X64 { public static partial class Program diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs index d02560343f145..1516d05d6d779 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -5,6 +5,7 @@ using System.Collections.Generic; [assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMAOT))] +[assembly:Xunit.ActiveIssue("https://github.com/dotnet/runtime/issues/75767", typeof(TestLibrary.PlatformDetection), nameof(TestLibrary.PlatformDetection.IsMonoLLVMFULLAOT))] namespace JIT.HardwareIntrinsics.X86._X86Base { public static partial class Program From a98dbde4bd547824388fcb410c06b2503a870fb6 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 24 Jan 2023 07:29:48 -0800 Subject: [PATCH 57/71] Add missing case for upper save/restore --- src/coreclr/jit/gentree.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index a6379f852992c..48d28cfe70f7f 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -12091,7 +12091,14 @@ void Compiler::gtDispTree(GenTree* tree, case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: printf(" isKnownConst"); break; - +#if defined(FEATURE_SIMD) + case NI_SIMD_UpperRestore: + printf(" simd_upperRestr"); + break; + case NI_SIMD_UpperSave: + printf(" simd_upperSave"); + break; +#endif // FEATURE_SIMD default: unreached(); } From 06f04609db53883abb25d67206dd6dbf6e30c338 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 25 Jan 2023 09:54:47 -0800 Subject: [PATCH 58/71] Add missing RequiresProcessIsolation --- src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj | 1 + src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj | 1 + 2 files changed, 2 insertions(+) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index b4db08053dcfc..33dd743607a76 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -5,6 +5,7 @@ true true + true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 13f9d7ab90504..3c1166d5c98d6 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -5,6 +5,7 @@ true true + true Embedded From 1b3e851127b3829c8623bb1e58c79ef9ef108d65 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 25 Jan 2023 09:55:41 -0800 Subject: [PATCH 59/71] Revert "Add missing case for upper save/restore" This reverts commit a98dbde4bd547824388fcb410c06b2503a870fb6. --- src/coreclr/jit/gentree.cpp | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 48d28cfe70f7f..a6379f852992c 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -12091,14 +12091,7 @@ void Compiler::gtDispTree(GenTree* tree, case NI_System_Runtime_CompilerServices_RuntimeHelpers_IsKnownConstant: printf(" isKnownConst"); break; -#if defined(FEATURE_SIMD) - case NI_SIMD_UpperRestore: - printf(" simd_upperRestr"); - break; - case NI_SIMD_UpperSave: - printf(" simd_upperSave"); - break; -#endif // FEATURE_SIMD + default: unreached(); } From 537f678ba88b6875fd3445ea431bb2d674ad3a5c Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 25 Jan 2023 10:48:41 -0800 Subject: [PATCH 60/71] Remove RequiresProcessIsolation property --- .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj | 1 - .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj | 1 - src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj | 1 - src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj | 1 - 4 files changed, 4 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index 4edd3d923fccd..f51cbcee5db90 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -5,7 +5,6 @@ true true - true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index fd8a772bfd8c1..2fd3b0ea3a269 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -5,7 +5,6 @@ true true - true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index 33dd743607a76..b4db08053dcfc 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -5,7 +5,6 @@ true true - true Embedded diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 3c1166d5c98d6..13f9d7ab90504 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -5,7 +5,6 @@ true true - true Embedded From e1b5fb38ce84c34f143e36be6aafc27ce820d8df Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 9 Feb 2023 15:05:41 -0800 Subject: [PATCH 61/71] Replace ref with fakelibs --- .../ref/System.Private.CoreLib.ExtraApis.cs | 16 ++++++++ .../ref/System.Private.CoreLib.ExtraApis.txt | 6 +++ .../ref/System.Runtime.Intrinsics.cs | 7 +--- .../src/CompatibilitySuppressions.xml | 40 +++++++++++++++++++ 4 files changed, 63 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 84e99da5aa050..5465d3601a7b7 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -37,3 +37,19 @@ public static partial class Debug public static System.Diagnostics.DebugProvider SetProvider(System.Diagnostics.DebugProvider provider) { throw null; } } } +namespace System.Runtime.Intrinsics.X86 +{ + public abstract partial class X86Base + { + public abstract partial class X64 + { + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } + } + + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } + } +} \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index 0babd819e25d0..66be9f8c4feec 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,3 +5,9 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, ulong upper, ulong divisor) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, long upper, long divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) \ No newline at end of file diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 9225956bc090a..47885edc44bda 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5210,23 +5210,18 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } + [System.CLSCompliantAttribute(false)] public abstract partial class X86Base { internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } - public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } - public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } - public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } - public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } public static bool IsSupported { get { throw null; } } - public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } - public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } } } diff --git a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml new file mode 100644 index 0000000000000..9c2f6856f8a25 --- /dev/null +++ b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml @@ -0,0 +1,40 @@ + + + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, ulong upper, ulong divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, long upper, long divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + \ No newline at end of file From 6589700d000484bcc102facd9f40eb4d86a9dec7 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Thu, 9 Feb 2023 22:03:33 -0800 Subject: [PATCH 62/71] Add references of fakelib to test project --- .../ref/System.Private.CoreLib.ExtraApis.txt | 4 ++-- .../src/CompatibilitySuppressions.xml | 8 ++++---- .../X86/X86Base.X64/Program.X86Base.X64.cs | 3 ++- .../X86/X86Base.X64/X86Base.X64_r.csproj | 1 + .../X86/X86Base.X64/X86Base.X64_ro.csproj | 1 + .../X86/X86Base/DivRem.csproj | 20 +++++++++++++++++++ .../X86/X86Base/Program.X86Base.cs | 3 ++- .../X86/X86Base/X86Base_r.csproj | 1 + .../X86/X86Base/X86Base_ro.csproj | 1 + 9 files changed, 34 insertions(+), 8 deletions(-) create mode 100644 src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index 66be9f8c4feec..ef258ffce6cdd 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,8 +5,8 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) -M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, ulong upper, ulong divisor) -M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, long upper, long divisor) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) diff --git a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml index 9c2f6856f8a25..a5580c72cd834 100644 --- a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml @@ -3,25 +3,25 @@ CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, ulong upper, ulong divisor) + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(ulong lower, long upper, long divisor) + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.UInt32 upper, System.UInt32 divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.Int32 upper, System.Int32 divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs index 7539c8c3014c3..4b5e06dfc9b9e 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - +extern alias CoreLib; +using X86Base.X64 = CoreLib::System.Runtime.Intrinsics.X86.X86Base.X64; using System; using System.Collections.Generic; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index f51cbcee5db90..6f077b94055b8 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -13,5 +13,6 @@ + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index 2fd3b0ea3a269..2374fbddb8b3c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -13,5 +13,6 @@ + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj new file mode 100644 index 0000000000000..a3cf7210497ba --- /dev/null +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj @@ -0,0 +1,20 @@ + + + + true + Library + SharedLibrary + System.Private.CoreLib + 436 + 436 + + + + + + \ No newline at end of file diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs index 1516d05d6d779..723b1829c38d9 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -1,6 +1,7 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. - +extern alias CoreLib; +using X86Base = CoreLib::System.Runtime.Intrinsics.X86.X86Base; using System; using System.Collections.Generic; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index b4db08053dcfc..074185ed16ab6 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -13,5 +13,6 @@ + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 13f9d7ab90504..00b1604afb45f 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -13,5 +13,6 @@ + From 2a90b4b06effb10c6a39b77505dacefdd5e98c01 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 10 Feb 2023 09:31:26 -0800 Subject: [PATCH 63/71] Fix CompatibilitySuppressions.xml --- .../CompatibilitySuppressions.xml | 21 ++++++++ .../src/CompatibilitySuppressions.xml | 48 ++++++++++++++++--- 2 files changed, 63 insertions(+), 6 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/CompatibilitySuppressions.xml b/src/coreclr/System.Private.CoreLib/CompatibilitySuppressions.xml index 6a201651f126a..ae179baa9c50e 100644 --- a/src/coreclr/System.Private.CoreLib/CompatibilitySuppressions.xml +++ b/src/coreclr/System.Private.CoreLib/CompatibilitySuppressions.xml @@ -1,3 +1,24 @@  + + + CP0001 + T:Internal.Console + + + CP0001 + T:System.Runtime.CompilerServices.ICastable + + + CP0002 + F:System.Resources.ResourceManager.BaseNameField + + + CP0002 + F:System.Resources.ResourceSet.Reader + + + CP0014 + M:System.Runtime.InteropServices.Marshal.CreateWrapperOfType(System.Object,System.Type)->object?:[T:System.Diagnostics.CodeAnalysis.NotNullIfNotNullAttribute] + \ No newline at end of file diff --git a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml index a5580c72cd834..3f4ec97bc8d07 100644 --- a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml +++ b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml @@ -1,15 +1,21 @@ - + CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.Int32 upper, System.Int32 divisor) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll @@ -21,19 +27,49 @@ CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.Int32 upper, System.Int32 divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.Int32,System.Int32) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.UInt32,System.UInt32) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.IntPtr,System.IntPtr) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.UIntPtr,System.UIntPtr) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.Int64,System.Int64) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.UInt64,System.UInt64) ref/net8.0/System.Runtime.Intrinsics.dll lib/net8.0/System.Runtime.Intrinsics.dll From aad300a6b3ebc4616aa4186c887f364f82972360 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 10 Feb 2023 09:49:30 -0800 Subject: [PATCH 64/71] fix test builds --- .../src/System/Runtime/Intrinsics/X86/X86Base.cs | 6 ++++++ .../X86/Shared/ScalarTernOpTupleBinRetTest.template | 3 ++- src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj | 1 + 3 files changed, 9 insertions(+), 1 deletion(-) diff --git a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs index 2a0b3e13919a2..6ba4107549e42 100644 --- a/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs +++ b/src/libraries/System.Private.CoreLib/src/System/Runtime/Intrinsics/X86/X86Base.cs @@ -10,7 +10,9 @@ namespace System.Runtime.Intrinsics.X86 /// This class provides access to the x86 base hardware instructions via intrinsics /// [Intrinsic] +#if SYSTEM_PRIVATE_CORELIB [CLSCompliant(false)] +#endif public abstract partial class X86Base { internal X86Base() { } @@ -87,9 +89,13 @@ internal X64() { } /// public static unsafe (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { +#if SYSTEM_PRIVATE_CORELIB int* cpuInfo = stackalloc int[4]; __cpuidex(cpuInfo, functionId, subFunctionId); return (cpuInfo[0], cpuInfo[1], cpuInfo[2], cpuInfo[3]); +#else + return (0, 0, 0, 0); +#endif } /// diff --git a/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template b/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template index 4f75049a57c64..e1e04ad6913cd 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template +++ b/src/tests/JIT/HardwareIntrinsics/X86/Shared/ScalarTernOpTupleBinRetTest.template @@ -7,7 +7,8 @@ * changes, please update the corresponding template and run according to the * * directions listed in the file. * ******************************************************************************/ - +extern alias CoreLib; +using X86Base = CoreLib::System.Runtime.Intrinsics.X86.X86Base; using System; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj index a3cf7210497ba..6d7e2bbf25b35 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj @@ -14,6 +14,7 @@ 436 + From eb3272c2e5a9b2b5159f4d29fc2cd27c92f1569d Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Fri, 10 Feb 2023 11:06:27 -0800 Subject: [PATCH 65/71] Remove unneeded extern/using --- .../HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs | 2 -- src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs | 2 -- 2 files changed, 4 deletions(-) diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs index 4b5e06dfc9b9e..40dc13b975f47 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/Program.X86Base.X64.cs @@ -1,7 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -extern alias CoreLib; -using X86Base.X64 = CoreLib::System.Runtime.Intrinsics.X86.X86Base.X64; using System; using System.Collections.Generic; diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs index 723b1829c38d9..364a8aee4b047 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/Program.X86Base.cs @@ -1,7 +1,5 @@ // Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. -extern alias CoreLib; -using X86Base = CoreLib::System.Runtime.Intrinsics.X86.X86Base; using System; using System.Collections.Generic; From 39ae98d2fee0c2b9d94437bce744c9f065654ed0 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Feb 2023 10:55:44 -0800 Subject: [PATCH 66/71] Revert "Replace ref with fakelibs" This reverts commit e1b5fb38ce84c34f143e36be6aafc27ce820d8df. --- .../ref/System.Private.CoreLib.ExtraApis.cs | 16 ---- .../ref/System.Private.CoreLib.ExtraApis.txt | 6 -- .../ref/System.Runtime.Intrinsics.cs | 7 +- .../src/CompatibilitySuppressions.xml | 76 ------------------- 4 files changed, 6 insertions(+), 99 deletions(-) delete mode 100644 src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 5465d3601a7b7..84e99da5aa050 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -37,19 +37,3 @@ public static partial class Debug public static System.Diagnostics.DebugProvider SetProvider(System.Diagnostics.DebugProvider provider) { throw null; } } } -namespace System.Runtime.Intrinsics.X86 -{ - public abstract partial class X86Base - { - public abstract partial class X64 - { - public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } - public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } - } - - public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } - public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } - public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } - public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } - } -} \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index ef258ffce6cdd..0babd819e25d0 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,9 +5,3 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) -M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) -M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) -M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) -M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) -M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) -M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) \ No newline at end of file diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 47885edc44bda..9225956bc090a 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5210,18 +5210,23 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } - [System.CLSCompliantAttribute(false)] public abstract partial class X86Base { internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } public static bool IsSupported { get { throw null; } } + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } } } diff --git a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml deleted file mode 100644 index 3f4ec97bc8d07..0000000000000 --- a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml +++ /dev/null @@ -1,76 +0,0 @@ - - - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.Int32 upper, System.Int32 divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.UInt32 upper, System.UInt32 divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.Int32,System.Int32) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.UInt32,System.UInt32) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.IntPtr,System.IntPtr) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.UIntPtr,System.UIntPtr) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.Int64,System.Int64) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - - CP0002 - M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.UInt64,System.UInt64) - ref/net8.0/System.Runtime.Intrinsics.dll - lib/net8.0/System.Runtime.Intrinsics.dll - - \ No newline at end of file From f8473eca63f4d5b67b5311ec86eef912db76e6ba Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Feb 2023 11:23:21 -0800 Subject: [PATCH 67/71] Revert "Revert "Replace ref with fakelibs"" This reverts commit 39ae98d2fee0c2b9d94437bce744c9f065654ed0. --- .../ref/System.Private.CoreLib.ExtraApis.cs | 16 ++++ .../ref/System.Private.CoreLib.ExtraApis.txt | 6 ++ .../ref/System.Runtime.Intrinsics.cs | 7 +- .../src/CompatibilitySuppressions.xml | 76 +++++++++++++++++++ 4 files changed, 99 insertions(+), 6 deletions(-) create mode 100644 src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs index 84e99da5aa050..5465d3601a7b7 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.cs @@ -37,3 +37,19 @@ public static partial class Debug public static System.Diagnostics.DebugProvider SetProvider(System.Diagnostics.DebugProvider provider) { throw null; } } } +namespace System.Runtime.Intrinsics.X86 +{ + public abstract partial class X86Base + { + public abstract partial class X64 + { + public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } + public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } + } + + public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } + public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } + public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } + public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } + } +} \ No newline at end of file diff --git a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt index 0babd819e25d0..ef258ffce6cdd 100644 --- a/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt +++ b/src/libraries/System.Private.CoreLib/ref/System.Private.CoreLib.ExtraApis.txt @@ -5,3 +5,9 @@ T:System.Runtime.Serialization.DeserializationToken M:System.Runtime.Serialization.SerializationInfo.StartDeserialization T:System.Diagnostics.DebugProvider M:System.Diagnostics.Debug.SetProvider(System.Diagnostics.DebugProvider) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) +M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(uint lower, uint upper, uint divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(int lower, int upper, int divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) +M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) \ No newline at end of file diff --git a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs index 9225956bc090a..47885edc44bda 100644 --- a/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs +++ b/src/libraries/System.Runtime.Intrinsics/ref/System.Runtime.Intrinsics.cs @@ -5210,23 +5210,18 @@ internal X64() { } public static new bool IsSupported { get { throw null; } } } } + [System.CLSCompliantAttribute(false)] public abstract partial class X86Base { internal X86Base() { } public static bool IsSupported { get { throw null; } } public static (int Eax, int Ebx, int Ecx, int Edx) CpuId(int functionId, int subFunctionId) { throw null; } - public static (uint Quotient, uint Remainder) DivRem(uint lower, uint upper, uint divisor) { throw null; } - public static (int Quotient, int Remainder) DivRem(uint lower, int upper, int divisor) { throw null; } - public static (nuint Quotient, nuint Remainder) DivRem(nuint lower, nuint upper, nuint divisor) { throw null; } - public static (nint Quotient, nint Remainder) DivRem(nuint lower, nint upper, nint divisor) { throw null; } public static void Pause() { throw null; } public abstract partial class X64 { internal X64() { } public static bool IsSupported { get { throw null; } } - public static (ulong Quotient, ulong Remainder) DivRem(ulong lower, ulong upper, ulong divisor) { throw null; } - public static (long Quotient, long Remainder) DivRem(ulong lower, long upper, long divisor) { throw null; } } } diff --git a/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml new file mode 100644 index 0000000000000..3f4ec97bc8d07 --- /dev/null +++ b/src/libraries/System.Runtime.Intrinsics/src/CompatibilitySuppressions.xml @@ -0,0 +1,76 @@ + + + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nint upper, nint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(nuint lower, nuint upper, nuint divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.Int32 upper, System.Int32 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32 lower, System.UInt32 upper, System.UInt32 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.Int32,System.Int32) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UInt32,System.UInt32,System.UInt32) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.IntPtr,System.IntPtr) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.DivRem(System.UIntPtr,System.UIntPtr,System.UIntPtr) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.Int64 upper, System.Int64 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64 lower, System.UInt64 upper, System.UInt64 divisor) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.Int64,System.Int64) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + + CP0002 + M:System.Runtime.Intrinsics.X86.X86Base.X64.DivRem(System.UInt64,System.UInt64,System.UInt64) + ref/net8.0/System.Runtime.Intrinsics.dll + lib/net8.0/System.Runtime.Intrinsics.dll + + \ No newline at end of file From e00a8c1f45b869e6e707a77496b3b22a0c9fde61 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Feb 2023 16:56:43 -0800 Subject: [PATCH 68/71] Exclude DivRem.csproj --- src/tests/issues.targets | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/tests/issues.targets b/src/tests/issues.targets index abce294dc9bc4..6704c64474293 100644 --- a/src/tests/issues.targets +++ b/src/tests/issues.targets @@ -1420,6 +1420,9 @@ https://github.com/dotnet/runtime/issues/75767 + + https://github.com/dotnet/runtime/issues/75767 + https://github.com/dotnet/runtime/issues/75767 @@ -2849,6 +2852,9 @@ https://github.com/dotnet/runtime/issues/75767 + + https://github.com/dotnet/runtime/issues/75767 + https://github.com/dotnet/runtime/issues/75767 @@ -3164,6 +3170,9 @@ https://github.com/dotnet/runtime/issues/75767 + + https://github.com/dotnet/runtime/issues/75767 + https://github.com/dotnet/runtime/issues/75767 From 9e282794abfc75d94dcb6a4cd6a273c25e524c60 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Mon, 13 Feb 2023 22:42:19 -0800 Subject: [PATCH 69/71] Handle the case to delay-free op3 for op1/op2 --- src/coreclr/jit/lsra.h | 6 +++- src/coreclr/jit/lsrabuild.cpp | 60 ++++++++++++++++++++++++++++++++--- src/coreclr/jit/lsraxarch.cpp | 21 +++++++++++- 3 files changed, 81 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index 3fe52664065ec..48de2822eac16 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -1866,7 +1866,11 @@ class LinearScan : public LinearScanInterface int BuildSimple(GenTree* tree); int BuildOperandUses(GenTree* node, regMaskTP candidates = RBM_NONE); - int BuildDelayFreeUses(GenTree* node, GenTree* rmwNode = nullptr, regMaskTP candidates = RBM_NONE); + void DelayFreeUses(RefPosition* refPosition, GenTree* rmwNode); + int BuildDelayFreeUses(GenTree* node, + GenTree* rmwNode = nullptr, + regMaskTP candidates = RBM_NONE, + RefPosition** useRefPosition = nullptr); int BuildIndirUses(GenTreeIndir* indirTree, regMaskTP candidates = RBM_NONE); int BuildAddrUses(GenTree* addr, regMaskTP candidates = RBM_NONE); void HandleFloatVarArgs(GenTreeCall* call, GenTree* argNode, bool* callHasFloatRegArgs); diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index 3908f1998792a..b5a3d80bc6b30 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3256,24 +3256,66 @@ void LinearScan::setDelayFree(RefPosition* use) pendingDelayFree = true; } +//------------------------------------------------------------------------ +// DelayFreeUses: Mark useRefPosition as delay-free, if applicable for the +// rmw node. +// +// Arguments: +// rmwNode - The node that has RMW semantics (if applicable) +// useRefPosition - The use refposition that need to be delay-freed. +// +void LinearScan::DelayFreeUses(RefPosition* useRefPosition, GenTree* rmwNode) +{ + assert(useRefPosition != nullptr); + + Interval* rmwInterval = nullptr; + bool rmwIsLastUse = false; + GenTree* addr = nullptr; + if ((rmwNode != nullptr) && isCandidateLocalRef(rmwNode)) + { + rmwInterval = getIntervalForLocalVarNode(rmwNode->AsLclVar()); + // Note: we don't handle multi-reg vars here. It's not clear that there are any cases + // where we'd encounter a multi-reg var in an RMW context. + assert(!rmwNode->AsLclVar()->IsMultiReg()); + rmwIsLastUse = rmwNode->AsLclVar()->IsLastUse(0); + } + // If node != rmwNode, then definitely node should be marked as "delayFree". + // However, if node == rmwNode, then we can mark node as "delayFree" only if + // none of the node/rmwNode are the last uses. If either of them are last use, + // we can safely reuse the rmwNode as destination. + if ((useRefPosition->getInterval() != rmwInterval) || (!rmwIsLastUse && !useRefPosition->lastUse)) + { + setDelayFree(useRefPosition); + } +} + //------------------------------------------------------------------------ // BuildDelayFreeUses: Build Use RefPositions for an operand that might be contained, // and which may need to be marked delayRegFree // // Arguments: -// node - The node of interest -// rmwNode - The node that has RMW semantics (if applicable) -// candidates - The set of candidates for the uses +// node - The node of interest +// rmwNode - The node that has RMW semantics (if applicable) +// candidates - The set of candidates for the uses +// useRefPositionRef - If a use refposition is created, returns it. If none created, sets it to nullptr. // // Return Value: // The number of source registers used by the *parent* of this node. // -int LinearScan::BuildDelayFreeUses(GenTree* node, GenTree* rmwNode, regMaskTP candidates) +int LinearScan::BuildDelayFreeUses(GenTree* node, + GenTree* rmwNode, + regMaskTP candidates, + RefPosition** useRefPositionRef) { RefPosition* use = nullptr; Interval* rmwInterval = nullptr; bool rmwIsLastUse = false; GenTree* addr = nullptr; + if (useRefPositionRef != nullptr) + { + *useRefPositionRef = nullptr; + } + if ((rmwNode != nullptr) && isCandidateLocalRef(rmwNode)) { rmwInterval = getIntervalForLocalVarNode(rmwNode->AsLclVar()); @@ -3328,6 +3370,11 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, GenTree* rmwNode, regMaskTP ca { setDelayFree(use); } + + if (useRefPositionRef != nullptr) + { + *useRefPositionRef = use; + } return 1; } @@ -3354,6 +3401,11 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, GenTree* rmwNode, regMaskTP ca } srcCount++; } + + if (useRefPositionRef != nullptr) + { + *useRefPositionRef = use; + } return srcCount; } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index 0aabc3debe323..fc35da9d1a828 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2178,7 +2178,26 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou // DIV implicitly put op1(lower) to EAX and op2(upper) to EDX srcCount += BuildOperandUses(op1, RBM_EAX); srcCount += BuildOperandUses(op2, RBM_EDX); - srcCount += op3->isContained() ? BuildOperandUses(op3) : BuildDelayFreeUses(op3, op1); + + if (!op3->isContained()) + { + // For non-contained nodes, we want to make sure we delay free the register for + // op3 with respect to both op1 and op2. In other words, op3 shouldn't get same + // register that is assigned to either of op1 and op2. + + RefPosition* op3RefPosition; + srcCount += BuildDelayFreeUses(op3, op1, RBM_NONE, &op3RefPosition); + if ((op3RefPosition != nullptr) && !op3RefPosition->delayRegFree) + { + // If op3 was not marked as delay-free for op1, mark it as delay-free + // if needed for op2. + DelayFreeUses(op3RefPosition, op2); + } + } + else + { + srcCount += BuildOperandUses(op3); + } // result put in EAX and EDX BuildDef(intrinsicTree, RBM_EAX, 0); From 2d4d8d9c6b84197fd0fe673d059627611660b0a1 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Tue, 14 Feb 2023 14:26:58 -0800 Subject: [PATCH 70/71] Create the DivRem.RefOnly fake CoreLib as a reference assembly Make the DivRem tests reference the DivRem fake CoreLib as reference assembly; and ensure that it is not included as a ProjectReference by the toplevel HardwareIntrinsics merged test runners. The upshot is that the DivRem tests can call the extra APIs via a direct reference to CoreLib (instead of through System.Runtime), but the fake library is not copied into any test artifact directories, and the Mono AOT compiler never sees it. --- src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj | 2 +- src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj | 2 +- .../JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj | 2 +- .../HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj | 2 +- .../X86/X86Base/{DivRem.csproj => DivRem.RefOnly.csproj} | 1 + src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj | 2 +- src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj | 2 +- 7 files changed, 7 insertions(+), 6 deletions(-) rename src/tests/JIT/HardwareIntrinsics/X86/X86Base/{DivRem.csproj => DivRem.RefOnly.csproj} (93%) diff --git a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj index d81af3a381450..9210387885675 100644 --- a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_r.csproj @@ -15,7 +15,7 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj index cec6dbb86c481..36d5b5608fede 100644 --- a/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/HardwareIntrinsics_ro.csproj @@ -16,7 +16,7 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj index 6f077b94055b8..d4c72bc89146c 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_r.csproj @@ -13,6 +13,6 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj index 2374fbddb8b3c..e0a62fa9bc562 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base.X64/X86Base.X64_ro.csproj @@ -13,6 +13,6 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.RefOnly.csproj similarity index 93% rename from src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj rename to src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.RefOnly.csproj index 6d7e2bbf25b35..1a70f52cd8874 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/DivRem.RefOnly.csproj @@ -12,6 +12,7 @@ System.Private.CoreLib 436 436 + true diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj index 074185ed16ab6..f16999cb670d1 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_r.csproj @@ -13,6 +13,6 @@ - + diff --git a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj index 00b1604afb45f..b09c5e72a5157 100644 --- a/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj +++ b/src/tests/JIT/HardwareIntrinsics/X86/X86Base/X86Base_ro.csproj @@ -13,6 +13,6 @@ - + From b5e3dd3a719d65ea6539d10baa9a5c2397d8c6c3 Mon Sep 17 00:00:00 2001 From: Kunal Pathak Date: Wed, 15 Feb 2023 10:09:38 -0800 Subject: [PATCH 71/71] Unify AddDelayFreeUses --- src/coreclr/jit/lsra.h | 2 +- src/coreclr/jit/lsrabuild.cpp | 50 +++++++++-------------------------- src/coreclr/jit/lsraxarch.cpp | 2 +- 3 files changed, 14 insertions(+), 40 deletions(-) diff --git a/src/coreclr/jit/lsra.h b/src/coreclr/jit/lsra.h index 48de2822eac16..888ca543d3f6a 100644 --- a/src/coreclr/jit/lsra.h +++ b/src/coreclr/jit/lsra.h @@ -1866,7 +1866,7 @@ class LinearScan : public LinearScanInterface int BuildSimple(GenTree* tree); int BuildOperandUses(GenTree* node, regMaskTP candidates = RBM_NONE); - void DelayFreeUses(RefPosition* refPosition, GenTree* rmwNode); + void AddDelayFreeUses(RefPosition* refPosition, GenTree* rmwNode); int BuildDelayFreeUses(GenTree* node, GenTree* rmwNode = nullptr, regMaskTP candidates = RBM_NONE, diff --git a/src/coreclr/jit/lsrabuild.cpp b/src/coreclr/jit/lsrabuild.cpp index b5a3d80bc6b30..e8638c7d15eb0 100644 --- a/src/coreclr/jit/lsrabuild.cpp +++ b/src/coreclr/jit/lsrabuild.cpp @@ -3257,14 +3257,14 @@ void LinearScan::setDelayFree(RefPosition* use) } //------------------------------------------------------------------------ -// DelayFreeUses: Mark useRefPosition as delay-free, if applicable for the -// rmw node. +// AddDelayFreeUses: Mark useRefPosition as delay-free, if applicable, for the +// rmw node. // // Arguments: -// rmwNode - The node that has RMW semantics (if applicable) -// useRefPosition - The use refposition that need to be delay-freed. +// useRefPosition - The use refposition that need to be delay-freed. +// rmwNode - The node that has RMW semantics (if applicable) // -void LinearScan::DelayFreeUses(RefPosition* useRefPosition, GenTree* rmwNode) +void LinearScan::AddDelayFreeUses(RefPosition* useRefPosition, GenTree* rmwNode) { assert(useRefPosition != nullptr); @@ -3307,23 +3307,13 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, regMaskTP candidates, RefPosition** useRefPositionRef) { - RefPosition* use = nullptr; - Interval* rmwInterval = nullptr; - bool rmwIsLastUse = false; - GenTree* addr = nullptr; + RefPosition* use = nullptr; + GenTree* addr = nullptr; if (useRefPositionRef != nullptr) { *useRefPositionRef = nullptr; } - if ((rmwNode != nullptr) && isCandidateLocalRef(rmwNode)) - { - rmwInterval = getIntervalForLocalVarNode(rmwNode->AsLclVar()); - // Note: we don't handle multi-reg vars here. It's not clear that there are any cases - // where we'd encounter a multi-reg var in an RMW context. - assert(!rmwNode->AsLclVar()->IsMultiReg()); - rmwIsLastUse = rmwNode->AsLclVar()->IsLastUse(0); - } if (!node->isContained()) { use = BuildUse(node, candidates); @@ -3362,19 +3352,7 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, } if (use != nullptr) { - // If node != rmwNode, then definitely node should be marked as "delayFree". - // However, if node == rmwNode, then we can mark node as "delayFree" only if - // none of the node/rmwNode are the last uses. If either of them are last use, - // we can safely reuse the rmwNode as destination. - if ((use->getInterval() != rmwInterval) || (!rmwIsLastUse && !use->lastUse)) - { - setDelayFree(use); - } - - if (useRefPositionRef != nullptr) - { - *useRefPositionRef = use; - } + AddDelayFreeUses(use, rmwNode); return 1; } @@ -3386,19 +3364,15 @@ int LinearScan::BuildDelayFreeUses(GenTree* node, if ((addrMode->Base() != nullptr) && !addrMode->Base()->isContained()) { use = BuildUse(addrMode->Base(), candidates); - if ((use->getInterval() != rmwInterval) || (!rmwIsLastUse && !use->lastUse)) - { - setDelayFree(use); - } + AddDelayFreeUses(use, rmwNode); + srcCount++; } if ((addrMode->Index() != nullptr) && !addrMode->Index()->isContained()) { use = BuildUse(addrMode->Index(), candidates); - if ((use->getInterval() != rmwInterval) || (!rmwIsLastUse && !use->lastUse)) - { - setDelayFree(use); - } + AddDelayFreeUses(use, rmwNode); + srcCount++; } diff --git a/src/coreclr/jit/lsraxarch.cpp b/src/coreclr/jit/lsraxarch.cpp index fc35da9d1a828..3b9b11def2cb5 100644 --- a/src/coreclr/jit/lsraxarch.cpp +++ b/src/coreclr/jit/lsraxarch.cpp @@ -2191,7 +2191,7 @@ int LinearScan::BuildHWIntrinsic(GenTreeHWIntrinsic* intrinsicTree, int* pDstCou { // If op3 was not marked as delay-free for op1, mark it as delay-free // if needed for op2. - DelayFreeUses(op3RefPosition, op2); + AddDelayFreeUses(op3RefPosition, op2); } } else