From 7f617e2a8c52939ad57ae04d0c9184e5cc019fed Mon Sep 17 00:00:00 2001 From: petris Date: Sat, 24 Jun 2023 21:53:05 +0200 Subject: [PATCH 01/44] Unify Default Comparer logic --- .../Collections/Generic/ComparerHelpers.cs | 75 ++----------------- src/coreclr/jit/compiler.h | 2 +- src/coreclr/jit/gentree.cpp | 5 +- src/coreclr/jit/importercalls.cpp | 22 +++--- .../EqualityComparerHelpers.cs | 4 + .../TypeSystem/IL/Stubs/ComparerIntrinsics.cs | 4 + src/coreclr/vm/jitinterface.cpp | 66 ++-------------- .../Devirtualization/Comparer_get_Default.cs | 26 +++++-- 8 files changed, 51 insertions(+), 153 deletions(-) diff --git a/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs index f07e70deaf8d88..edebcfa6a612c6 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs @@ -46,44 +46,12 @@ internal static object CreateDefaultComparer(Type type) // The comparer for enums is specialized to avoid boxing. else if (type.IsEnum) { - result = TryCreateEnumComparer(runtimeType); + result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumComparer<>), runtimeType); } return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectComparer), runtimeType); } - /// - /// Creates the default for an enum type. - /// - /// The enum type to create the default comparer for. - private static object? TryCreateEnumComparer(RuntimeType enumType) - { - Debug.Assert(enumType != null); - Debug.Assert(enumType.IsEnum); - - // Explicitly call Enum.GetUnderlyingType here. Although GetTypeCode - // ends up doing this anyway, we end up avoiding an unnecessary P/Invoke - // and virtual method call. - TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType)); - - // Depending on the enum type, we need to special case the comparers so that we avoid boxing. - // Specialize differently for signed/unsigned types so we avoid problems with large numbers. - switch (underlyingTypeCode) - { - case TypeCode.SByte: - case TypeCode.Int16: - case TypeCode.Int32: - case TypeCode.Byte: - case TypeCode.UInt16: - case TypeCode.UInt32: - case TypeCode.Int64: - case TypeCode.UInt64: - return CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumComparer<>), enumType); - } - - return null; - } - /// /// Creates the default . /// @@ -103,11 +71,6 @@ internal static object CreateDefaultEqualityComparer(Type type) // Specialize for byte so Array.IndexOf is faster. result = new ByteEqualityComparer(); } - else if (type == typeof(string)) - { - // Specialize for string, as EqualityComparer.Default is on the startup path - result = new GenericEqualityComparer(); - } else if (type.IsAssignableTo(typeof(IEquatable<>).MakeGenericType(type))) { // If T implements IEquatable return a GenericEqualityComparer @@ -122,41 +85,13 @@ internal static object CreateDefaultEqualityComparer(Type type) else if (type.IsEnum) { // The equality comparer for enums is specialized to avoid boxing. - result = TryCreateEnumEqualityComparer(runtimeType); - } - - return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectEqualityComparer), runtimeType); - } - - /// - /// Creates the default for an enum type. - /// - /// The enum type to create the default equality comparer for. - private static object? TryCreateEnumEqualityComparer(RuntimeType enumType) - { - Debug.Assert(enumType != null); - Debug.Assert(enumType.IsEnum); - - // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation - // for how we cast the enum types to integral values in the comparer without boxing. - TypeCode underlyingTypeCode = Type.GetTypeCode(Enum.GetUnderlyingType(enumType)); - - // Depending on the enum type, we need to special case the comparers so that we avoid boxing. - switch (underlyingTypeCode) - { - case TypeCode.Int32: - case TypeCode.UInt32: - case TypeCode.SByte: - case TypeCode.Byte: - case TypeCode.Int16: - case TypeCode.Int64: - case TypeCode.UInt64: - case TypeCode.UInt16: - return CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<>), enumType); + // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation + // for how we cast the enum types to integral values in the comparer without boxing. + result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<>), runtimeType); } - return null; + return result ?? CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(ObjectEqualityComparer), runtimeType); } } } diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index 0d24478ae115d8..b405b9a3b6ec10 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3873,7 +3873,7 @@ class Compiler CORINFO_CALL_INFO* callInfo, IL_OFFSET rawILOffset); - CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(GenTreeCall* call); + CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(GenTreeCall* call, bool* pIsExact); GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd); diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 6fdbeebc666fe2..990751e32b82f9 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17963,11 +17963,12 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b break; } - CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call); + bool isExact = false; + CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call, &isExact); if (specialObjClass != nullptr) { objClass = specialObjClass; - *pIsExact = true; + *pIsExact = isExact; *pIsNonNull = true; break; } diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index eb67240252e6ae..f6ef0ceb56d9fd 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7483,16 +7483,18 @@ Compiler::GDVProbeType Compiler::compClassifyGDVProbeType(GenTreeCall* call) // // Arguments: // methodHnd -- handle for the special intrinsic method +// pIsExact -- returns whether the type is exact // // Returns: // Exact class handle returned by the intrinsic call, if known. // Nullptr if not known, or not likely to lead to beneficial optimization. -CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall* call) +CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall* call, bool* pIsExact) { CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; JITDUMP("Special intrinsic: looking for exact type returned by %s\n", eeGetMethodFullName(methodHnd)); CORINFO_CLASS_HANDLE result = nullptr; + *pIsExact = false; // See what intrinsic we have... const NamedIntrinsic ni = lookupNamedIntrinsic(methodHnd); @@ -7510,15 +7512,10 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall // Lookup can incorrect when we have __Canon as it won't appear // to implement any interface types. - // - // And if we do not have a final type, devirt & inlining is - // unlikely to result in much simplification. - // - // We can use CORINFO_FLG_FINAL to screen out both of these cases. const DWORD typeAttribs = info.compCompHnd->getClassAttribs(typeHnd); - bool isFinalType = ((typeAttribs & CORINFO_FLG_FINAL) != 0); + bool isNonShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) != 0); - if (!isFinalType) + if (!isNonShared) { CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); if (instParam != nullptr) @@ -7528,16 +7525,16 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall if (hClass != NO_CLASS_HANDLE) { hClass = getTypeInstantiationArgument(hClass, 0); - if ((info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_FINAL) != 0) + if ((info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_SHAREDINST) != 0) { typeHnd = hClass; - isFinalType = true; + isNonShared = true; } } } } - if (isFinalType) + if (isNonShared) { if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default) { @@ -7548,12 +7545,13 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall assert(ni == NI_System_Collections_Generic_Comparer_get_Default); result = info.compCompHnd->getDefaultComparerClass(typeHnd); } + *pIsExact = result != nullptr; JITDUMP("Special intrinsic for type %s: return type is %s\n", eeGetClassName(typeHnd), result != nullptr ? eeGetClassName(result) : "unknown"); } else { - JITDUMP("Special intrinsic for type %s: type not final, so deferring opt\n", eeGetClassName(typeHnd)); + JITDUMP("Special intrinsic for type %s: type shared, so deferring opt\n", eeGetClassName(typeHnd)); } break; diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs index dc63cad6caeb69..f4980d447b0ef6 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs @@ -59,6 +59,10 @@ internal static object GetComparer(RuntimeTypeHandle t) RuntimeTypeHandle openComparerType = default(RuntimeTypeHandle); RuntimeTypeHandle comparerTypeArgument = default(RuntimeTypeHandle); + if (t == typeof(byte).TypeHandle) + { + return new ByteEqualityComparer(); + } if (RuntimeAugments.IsNullable(t)) { RuntimeTypeHandle nullableType = RuntimeAugments.GetNullableType(t); diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs index 95a29ae04fc181..7c97549d698f64 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs @@ -85,6 +85,10 @@ private static InstantiatedType GetComparerForType(TypeDesc type, string flavor, // The comparer will be determined at runtime. We can't tell the exact type at compile time. return null; } + else if (flavor == "EqualityComparer" && type.GetRuntimeTypeHandle() == typeof(byte).TypeHandle) + { + return context.SystemModule.GetKnownType("System.Collections.Generic", $"ByteEqualityComparer"); + } else if (type.IsNullable) { TypeDesc nullableType = type.Instantiation[0]; diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index 28c7b9eeb982c7..fecfec31298302 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8741,44 +8741,15 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE if (Nullable::IsNullableType(elemTypeHnd)) { Instantiation nullableInst = elemTypeHnd.AsMethodTable()->GetInstantiation(); - TypeHandle iequatable = TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(nullableInst); - if (nullableInst[0].CanCastTo(iequatable)) - { - TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_COMPARER)).Instantiate(nullableInst); - return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); - } + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__NULLABLE_COMPARER)).Instantiate(nullableInst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } // We need to special case the Enum comparers based on their underlying type to avoid boxing if (elemTypeHnd.IsEnum()) { - MethodTable* targetClass = NULL; - CorElementType normType = elemTypeHnd.GetVerifierCorElementType(); - - switch(normType) - { - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - { - targetClass = CoreLibBinder::GetClass(CLASS__ENUM_COMPARER); - break; - } - - default: - break; - } - - if (targetClass != NULL) - { - TypeHandle resultTh = ((TypeHandle)targetClass->GetCanonicalMethodTable()).Instantiate(inst); - return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); - } + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_COMPARER)).Instantiate(inst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } // Default case @@ -8852,33 +8823,8 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // to avoid boxing and call the correct versions of GetHashCode. if (elemTypeHnd.IsEnum()) { - MethodTable* targetClass = NULL; - CorElementType normType = elemTypeHnd.GetVerifierCorElementType(); - - switch(normType) - { - case ELEMENT_TYPE_I1: - case ELEMENT_TYPE_I2: - case ELEMENT_TYPE_U1: - case ELEMENT_TYPE_U2: - case ELEMENT_TYPE_I4: - case ELEMENT_TYPE_U4: - case ELEMENT_TYPE_I8: - case ELEMENT_TYPE_U8: - { - targetClass = CoreLibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER); - break; - } - - default: - break; - } - - if (targetClass != NULL) - { - TypeHandle resultTh = ((TypeHandle)targetClass->GetCanonicalMethodTable()).Instantiate(inst); - return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); - } + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__ENUM_EQUALITYCOMPARER)).Instantiate(inst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } // Default case diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 6a8b09163d7765..dd7fd797f637c3 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -92,19 +92,19 @@ private static void Compare_Int32_Nullable(long? a, long? b) [Fact] public static int TestEntryPoint() { - long[] values = + long[] values = { -2, -1, 0, 1, 2, - sbyte.MinValue - 1, sbyte.MinValue, sbyte.MinValue + 1, + sbyte.MinValue - 1, sbyte.MinValue, sbyte.MinValue + 1, sbyte.MaxValue - 1, sbyte.MaxValue, sbyte.MaxValue + 1, byte.MaxValue - 1, byte.MaxValue, byte.MaxValue + 1, - short.MinValue, short.MinValue + 1, + short.MinValue, short.MinValue + 1, short.MaxValue - 1, short.MaxValue, short.MaxValue + 1, ushort.MaxValue - 1, ushort.MaxValue, ushort.MaxValue + 1, - int.MinValue, int.MinValue + 1, + int.MinValue, int.MinValue + 1, int.MaxValue - 1, int.MaxValue, int.MaxValue + 1L, uint.MaxValue - 1, uint.MaxValue, uint.MaxValue + 1L, - long.MinValue, long.MinValue + 1, + long.MinValue, long.MinValue + 1, long.MaxValue - 1, long.MaxValue }; @@ -217,16 +217,26 @@ public static int TestEntryPoint() private static void GetTypeTests() { + AssertEquals("System.Collections.Generic.GenericComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[System.String]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[System.Guid]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.EnumComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct1]", Comparer.Default.GetType().ToString()); - + AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct1]", Comparer.Default.GetType().ToString()); + + AssertEquals("System.Collections.Generic.ByteEqualityComparer", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.String]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Guid]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); } private static int GetHashCodeTests() From 2536992d11b86a3f34360b62e9d6ba9b1aaa964e Mon Sep 17 00:00:00 2001 From: petris Date: Sat, 24 Jun 2023 22:25:04 +0200 Subject: [PATCH 02/44] Fix build --- src/coreclr/jit/gentree.cpp | 2 +- src/coreclr/jit/importercalls.cpp | 2 +- .../tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index 990751e32b82f9..f749c7059142b7 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17963,7 +17963,7 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b break; } - bool isExact = false; + bool isExact = false; CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call, &isExact); if (specialObjClass != nullptr) { diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index f6ef0ceb56d9fd..a4dbe10a979da9 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7494,7 +7494,7 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall JITDUMP("Special intrinsic: looking for exact type returned by %s\n", eeGetMethodFullName(methodHnd)); CORINFO_CLASS_HANDLE result = nullptr; - *pIsExact = false; + *pIsExact = false; // See what intrinsic we have... const NamedIntrinsic ni = lookupNamedIntrinsic(methodHnd); diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs index 7c97549d698f64..9d6cedea6fae85 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs @@ -75,7 +75,7 @@ private static MethodIL EmitComparerAndEqualityComparerCreateCommon(MethodDesc m /// Gets the comparer type that is suitable to compare instances of /// or null if such comparer cannot be determined at compile time. /// - private static InstantiatedType GetComparerForType(TypeDesc type, string flavor, string interfaceName) + private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string interfaceName) { TypeSystemContext context = type.Context; @@ -85,7 +85,7 @@ private static InstantiatedType GetComparerForType(TypeDesc type, string flavor, // The comparer will be determined at runtime. We can't tell the exact type at compile time. return null; } - else if (flavor == "EqualityComparer" && type.GetRuntimeTypeHandle() == typeof(byte).TypeHandle) + else if (flavor == "EqualityComparer" && context.SystemModule.GetKnownType("System", "Byte").Equals(type)) { return context.SystemModule.GetKnownType("System.Collections.Generic", $"ByteEqualityComparer"); } From 5605e0eb3e2a71695f128d9e9009bfeaeacf3260 Mon Sep 17 00:00:00 2001 From: petris Date: Sat, 24 Jun 2023 22:41:17 +0200 Subject: [PATCH 03/44] Fix build --- .../src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs index f4980d447b0ef6..921e22c8586454 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs @@ -59,7 +59,7 @@ internal static object GetComparer(RuntimeTypeHandle t) RuntimeTypeHandle openComparerType = default(RuntimeTypeHandle); RuntimeTypeHandle comparerTypeArgument = default(RuntimeTypeHandle); - if (t == typeof(byte).TypeHandle) + if (typeof(byte).TypeHandle.Equals(t)) { return new ByteEqualityComparer(); } From 72e548ade10c475ff52326647f13c2f1c5b0cf2a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sun, 25 Jun 2023 03:43:07 +0200 Subject: [PATCH 04/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index a4dbe10a979da9..984e740ef05b5e 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7513,7 +7513,7 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall // Lookup can incorrect when we have __Canon as it won't appear // to implement any interface types. const DWORD typeAttribs = info.compCompHnd->getClassAttribs(typeHnd); - bool isNonShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) != 0); + bool isNonShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) == 0); if (!isNonShared) { From 9d9fc84690e317c85e3aad5ca44c95c066a06063 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sun, 25 Jun 2023 03:44:40 +0200 Subject: [PATCH 05/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 984e740ef05b5e..e625716f1753da 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7513,9 +7513,9 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall // Lookup can incorrect when we have __Canon as it won't appear // to implement any interface types. const DWORD typeAttribs = info.compCompHnd->getClassAttribs(typeHnd); - bool isNonShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) == 0); + bool isShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) != 0); - if (!isNonShared) + if (isShared) { CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); if (instParam != nullptr) @@ -7525,16 +7525,16 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall if (hClass != NO_CLASS_HANDLE) { hClass = getTypeInstantiationArgument(hClass, 0); - if ((info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_SHAREDINST) != 0) + if ((info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_SHAREDINST) == 0) { - typeHnd = hClass; - isNonShared = true; + typeHnd = hClass; + isShared = false; } } } } - if (isNonShared) + if (!isShared) { if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default) { From f229039f913d24e864d13541e1557ad6edcc4d37 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sun, 25 Jun 2023 14:11:28 +0200 Subject: [PATCH 06/44] Update Comparer_get_Default.cs --- .../Devirtualization/Comparer_get_Default.cs | 102 ++++++++++++++++-- 1 file changed, 94 insertions(+), 8 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index dd7fd797f637c3..385b9037f2b763 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -21,6 +21,23 @@ private static void AssertEquals(T expected, T actual, [CallerLineNumber] int } } + private static void AssertThrows(Action action, [CallerLineNumber] int line = 0) where T : Exception + { + try + { + action(); + Console.WriteLine($"no {typeof(TException).FullName}, L{line}"); + s_ReturnCode++; + } + catch (Exception ex) + { + if (ex.GetType() == typeof(TException)) + return; + Console.WriteLine($"{ex.GetType().FullName} != {typeof(TException).FullName}, L{line}"); + s_ReturnCode++; + } + } + private static void Compare_Boolean(Boolean a, Boolean b) => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); @@ -75,9 +92,6 @@ private static void Compare_String(String a, String b) => private static void Compare_DateTime(DateTime a, DateTime b) => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); - private static void Compare_Struct1(Struct1 a, Struct1 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); - private static void Compare_Int32_Nullable(long? a, long? b) { int actual = Comparer.Default.Compare(a, b); @@ -89,6 +103,38 @@ private static void Compare_Int32_Nullable(long? a, long? b) AssertEquals(expected, actual); } + private static void Compare_Enum_Int32_Nullable(MethodImplOptions? a, MethodImplOptions? b) + { + int actual = Comparer.Default.Compare(a, b); + int expected = 0; + if (a.HasValue) + expected = b.HasValue ? a.Value.CompareTo(b.Value) : 1; + else + expected = b.HasValue ? -1 : 0; + AssertEquals(expected, actual); + } + + private static void Compare_Struct1(Struct1 a, Struct1 b) => + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + + private static void Compare_Struct2(Struct2 a, Struct2 b) => + AssertThrows(() => Comparer.Default.Compare(a, b)); + + private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + + private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) + { + if (a.IsNull && b.IsNull) + AssertEquals(0, Comparer.Default.Compare(a, b)); + else if (a.IsNull) + AssertEquals(-1, Comparer.Default.Compare(a, b)); + else if (b.IsNull) + AssertEquals(1, Comparer.Default.Compare(a, b)); + else + AssertThrows(() => Comparer.Default.Compare(a, b)); + } + [Fact] public static int TestEntryPoint() { @@ -179,15 +225,41 @@ public static int TestEntryPoint() var enumByteB = Unsafe.As(ref b); Compare_Enum_Byte(enumByteA, enumByteB); - var structA = new Struct1 {a = a, b = b}; - var structB = new Struct1 {a = b, b = a}; - Compare_Struct1(structA, structB); - Compare_DateTime( new DateTime(Math.Clamp(a, DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks)), new DateTime(Math.Clamp(b, DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks))); Compare_Int32_Nullable(a, b); + Compare_Enum_Int32_Nullable(enumIntA, enumByteB); + + Compare_Int32_Nullable(null, b); + Compare_Enum_Int32_Nullable(null, enumByteB); + + Compare_Int32_Nullable(a, null); + Compare_Enum_Int32_Nullable(enumIntA, null); + + Compare_Int32_Nullable(null, null); + Compare_Enum_Int32_Nullable(null, null); + + var structA = new Struct1 {a = a, b = b}; + var structB = new Struct1 {a = b, b = a}; + Compare_Struct1(structA, structB); + + var struct2A = new Struct2 {a = a, b = b}; + var struct2B = new Struct2 {a = b, b = a}; + Compare_Struct2(struct2A, struct2B); + + Compare_Struct1_Nullable(structA, structB); + Compare_Struct2_Nullable(struct2A, struct2B); + + Compare_Struct1_Nullable(null, structB); + Compare_Struct2_Nullable(null, struct2B); + + Compare_Struct1_Nullable(structA, null); + Compare_Struct2_Nullable(struct2A, null); + + Compare_Struct1_Nullable(null, null); + Compare_Struct2_Nullable(null, null); } } @@ -223,10 +295,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.GenericComparer`1[System.Guid]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.EnumComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct1]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct1]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ByteEqualityComparer", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); @@ -234,10 +308,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Guid]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); } private static int GetHashCodeTests() { @@ -245,9 +321,13 @@ private static int GetHashCodeTests() return Comparer.Default.GetHashCode() + Comparer.Default.GetHashCode() + Comparer.Default.GetHashCode() + + Comparer.Default.GetHashCode() + Comparer.Default.GetHashCode() + Comparer.Default.GetHashCode() + - Comparer.Default.GetHashCode(); + Comparer.Default.GetHashCode() + + Comparer.Default.GetHashCode() + + Comparer.Default.GetHashCode() + + Comparer.Default.GetHashCode(); } } @@ -265,3 +345,9 @@ public int CompareTo(object obj) return b.CompareTo(((Struct1) obj).b); } } + +public struct Struct2 +{ + public long a; + public long b; +} From 70cb1c0a7b024d7c7139cec6a6bee5b1f1274754 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sun, 25 Jun 2023 15:12:52 +0200 Subject: [PATCH 07/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 385b9037f2b763..f0f17089e36ede 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -21,7 +21,7 @@ private static void AssertEquals(T expected, T actual, [CallerLineNumber] int } } - private static void AssertThrows(Action action, [CallerLineNumber] int line = 0) where T : Exception + private static void AssertThrows(Action action, [CallerLineNumber] int line = 0) where TException : Exception { try { From e095936cc3e6b460212f591e2ff2a3139eb054f5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sun, 25 Jun 2023 16:50:05 +0200 Subject: [PATCH 08/44] Update Comparer_get_Default.cs --- .../JIT/opt/Devirtualization/Comparer_get_Default.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index f0f17089e36ede..033b836a343a6f 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -121,15 +121,15 @@ private static void Compare_Struct2(Struct2 a, Struct2 b) => AssertThrows(() => Comparer.Default.Compare(a, b)); private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(((object)a).CompareTo(b), Comparer.Default.Compare(a, b)); private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { - if (a.IsNull && b.IsNull) + if (a.HasValue && b.HasValue) AssertEquals(0, Comparer.Default.Compare(a, b)); - else if (a.IsNull) + else if (a.HasValue) AssertEquals(-1, Comparer.Default.Compare(a, b)); - else if (b.IsNull) + else if (b.HasValue) AssertEquals(1, Comparer.Default.Compare(a, b)); else AssertThrows(() => Comparer.Default.Compare(a, b)); From d591efe844aa690b3d6f6c8ce1e1d0084d94daec Mon Sep 17 00:00:00 2001 From: petris Date: Sun, 25 Jun 2023 23:24:30 +0200 Subject: [PATCH 09/44] Apply sugestions --- .../Collections/Generic/ComparerHelpers.cs | 8 +-- .../EqualityComparerHelpers.cs | 4 -- .../TypeSystem/IL/Stubs/ComparerIntrinsics.cs | 4 -- src/coreclr/vm/corelib.h | 1 - .../Generic/EqualityComparer.Mono.cs | 6 +- .../Devirtualization/Comparer_get_Default.cs | 71 ++++++++++++++++--- .../Comparer_get_Default.csproj | 3 + .../JIT/opt/Devirtualization/UncommonEnums.il | 42 +++++++++++ .../opt/Devirtualization/UncommonEnums.ilproj | 11 +++ 9 files changed, 119 insertions(+), 31 deletions(-) create mode 100644 src/tests/JIT/opt/Devirtualization/UncommonEnums.il create mode 100644 src/tests/JIT/opt/Devirtualization/UncommonEnums.ilproj diff --git a/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs b/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs index edebcfa6a612c6..87c07da9cdb38b 100644 --- a/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs +++ b/src/coreclr/System.Private.CoreLib/src/System/Collections/Generic/ComparerHelpers.cs @@ -66,10 +66,9 @@ internal static object CreateDefaultEqualityComparer(Type type) object? result = null; var runtimeType = (RuntimeType)type; - if (type == typeof(byte)) + if (type == typeof(string)) { - // Specialize for byte so Array.IndexOf is faster. - result = new ByteEqualityComparer(); + return new GenericEqualityComparer(); } else if (type.IsAssignableTo(typeof(IEquatable<>).MakeGenericType(type))) { @@ -85,9 +84,6 @@ internal static object CreateDefaultEqualityComparer(Type type) else if (type.IsEnum) { // The equality comparer for enums is specialized to avoid boxing. - - // See the METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST and METHOD__JIT_HELPERS__UNSAFE_ENUM_CAST_LONG cases in getILIntrinsicImplementation - // for how we cast the enum types to integral values in the comparer without boxing. result = CreateInstanceForAnotherGenericParameter((RuntimeType)typeof(EnumEqualityComparer<>), runtimeType); } diff --git a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs index 921e22c8586454..dc63cad6caeb69 100644 --- a/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs +++ b/src/coreclr/nativeaot/System.Private.CoreLib/src/Internal/IntrinsicSupport/EqualityComparerHelpers.cs @@ -59,10 +59,6 @@ internal static object GetComparer(RuntimeTypeHandle t) RuntimeTypeHandle openComparerType = default(RuntimeTypeHandle); RuntimeTypeHandle comparerTypeArgument = default(RuntimeTypeHandle); - if (typeof(byte).TypeHandle.Equals(t)) - { - return new ByteEqualityComparer(); - } if (RuntimeAugments.IsNullable(t)) { RuntimeTypeHandle nullableType = RuntimeAugments.GetNullableType(t); diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs index 9d6cedea6fae85..2c966d16291aca 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs @@ -85,10 +85,6 @@ private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string // The comparer will be determined at runtime. We can't tell the exact type at compile time. return null; } - else if (flavor == "EqualityComparer" && context.SystemModule.GetKnownType("System", "Byte").Equals(type)) - { - return context.SystemModule.GetKnownType("System.Collections.Generic", $"ByteEqualityComparer"); - } else if (type.IsNullable) { TypeDesc nullableType = type.Instantiation[0]; diff --git a/src/coreclr/vm/corelib.h b/src/coreclr/vm/corelib.h index ddd3bb66c98b66..7c903e9f532920 100644 --- a/src/coreclr/vm/corelib.h +++ b/src/coreclr/vm/corelib.h @@ -1178,7 +1178,6 @@ DEFINE_METHOD(UTF8BUFFERMARSHALER, CONVERT_TO_MANAGED, ConvertToManaged, NoSig) // Classes referenced in EqualityComparer.Default optimization -DEFINE_CLASS(BYTE_EQUALITYCOMPARER, CollectionsGeneric, ByteEqualityComparer) DEFINE_CLASS(ENUM_EQUALITYCOMPARER, CollectionsGeneric, EnumEqualityComparer`1) DEFINE_CLASS(NULLABLE_EQUALITYCOMPARER, CollectionsGeneric, NullableEqualityComparer`1) DEFINE_CLASS(GENERIC_EQUALITYCOMPARER, CollectionsGeneric, GenericEqualityComparer`1) diff --git a/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs b/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs index 603c1603290678..6d6bb681e1a9e7 100644 --- a/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs +++ b/src/mono/System.Private.CoreLib/src/System/Collections/Generic/EqualityComparer.Mono.cs @@ -35,11 +35,7 @@ private static EqualityComparer CreateComparer() // IN mini_handle_call_res_devirt ///////////////////////////////////////////////// - if (t == typeof(byte)) - { - return (EqualityComparer)(object)(new ByteEqualityComparer()); - } - else if (t == typeof(string)) + if (t == typeof(string)) { // Specialize for string, as EqualityComparer.Default is on the startup path return (EqualityComparer)(object)(new GenericEqualityComparer()); diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 033b836a343a6f..aca0d7a9ec309b 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -116,13 +116,13 @@ private static void Compare_Enum_Int32_Nullable(MethodImplOptions? a, MethodImpl private static void Compare_Struct1(Struct1 a, Struct1 b) => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); - + private static void Compare_Struct2(Struct2 a, Struct2 b) => AssertThrows(() => Comparer.Default.Compare(a, b)); private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => - AssertEquals(((object)a).CompareTo(b), Comparer.Default.Compare(a, b)); - + AssertEquals(((IComparable)a).CompareTo(b), Comparer.Default.Compare(a, b)); + private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { if (a.HasValue && b.HasValue) @@ -135,6 +135,9 @@ private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) AssertThrows(() => Comparer.Default.Compare(a, b)); } + private static void Compare_Generic_Enum(TEnum a, TEnum b) where TEnum : Enum => + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + [Fact] public static int TestEntryPoint() { @@ -151,7 +154,7 @@ public static int TestEntryPoint() int.MaxValue - 1, int.MaxValue, int.MaxValue + 1L, uint.MaxValue - 1, uint.MaxValue, uint.MaxValue + 1L, long.MinValue, long.MinValue + 1, - long.MaxValue - 1, long.MaxValue + long.MaxValue - 1, long.MaxValue, BitConverter.DoubleToInt64Bits(double.NaN) }; for (var i = 0; i < values.Length; i++) @@ -230,20 +233,17 @@ public static int TestEntryPoint() new DateTime(Math.Clamp(b, DateTime.MinValue.Ticks, DateTime.MaxValue.Ticks))); Compare_Int32_Nullable(a, b); - Compare_Enum_Int32_Nullable(enumIntA, enumByteB); + Compare_Enum_Int32_Nullable(enumIntA, enumIntB); Compare_Int32_Nullable(null, b); - Compare_Enum_Int32_Nullable(null, enumByteB); + Compare_Enum_Int32_Nullable(null, enumIntB); Compare_Int32_Nullable(a, null); Compare_Enum_Int32_Nullable(enumIntA, null); - Compare_Int32_Nullable(null, null); - Compare_Enum_Int32_Nullable(null, null); - var structA = new Struct1 {a = a, b = b}; var structB = new Struct1 {a = b, b = a}; - Compare_Struct1(structA, structB); + Compare_Struct1(structA, structB); var struct2A = new Struct2 {a = a, b = b}; var struct2B = new Struct2 {a = b, b = a}; @@ -260,6 +260,30 @@ public static int TestEntryPoint() Compare_Struct1_Nullable(null, null); Compare_Struct2_Nullable(null, null); + + var enumCharA = Unsafe.As(ref a); + var enumCharB = Unsafe.As(ref b); + Compare_Generic_Enum(enumCharA, enumCharB); + + var enumBoolA = Unsafe.As(ref a); + var enumBoolB = Unsafe.As(ref b); + Compare_Generic_Enum(enumBoolA, enumBoolB); + + var enumFloatA = Unsafe.As(ref a); + var enumFloatB = Unsafe.As(ref b); + Compare_Generic_Enum(enumFloatA, enumFloatB); + + var enumDoubleA = Unsafe.As(ref a); + var enumDoubleB = Unsafe.As(ref b); + Compare_Generic_Enum(enumDoubleA, enumDoubleB); + + var enumIntPtrA = Unsafe.As(ref a); + var enumIntPtrB = Unsafe.As(ref b); + Compare_Generic_Enum(enumIntPtrA, enumIntPtrB); + + var enumUIntPtrA = Unsafe.As(ref a); + var enumUIntPtrB = Unsafe.As(ref b); + Compare_Generic_Enum(enumUIntPtrA, enumUIntPtrB); } } @@ -280,6 +304,7 @@ public static int TestEntryPoint() Compare_Int32_Nullable(1, null); Compare_Int32_Nullable(null, -1); Compare_Int32_Nullable(-1, null); + Compare_Enum_Int32_Nullable(null, null); GetTypeTests(); GetHashCodeTests(); @@ -294,24 +319,48 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.GenericComparer`1[System.String]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[System.Guid]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.EnumComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[CharEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[BoolEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[FloatEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[DoubleEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[IntPtrEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumComparer`1[UIntPtrEnum]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct1]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[CharEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[BoolEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[FloatEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[DoubleEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[IntPtrEnum]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[UIntPtrEnum]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct1]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct2]", Comparer.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ByteEqualityComparer", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.String]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Guid]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[CharEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[BoolEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[FloatEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[DoubleEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[IntPtrEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[UIntPtrEnum]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[CharEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[BoolEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[FloatEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[DoubleEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[IntPtrEnum]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[UIntPtrEnum]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); } diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj index 669603b68d88e8..4659c691ffe6d0 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj @@ -5,4 +5,7 @@ + + + diff --git a/src/tests/JIT/opt/Devirtualization/UncommonEnums.il b/src/tests/JIT/opt/Devirtualization/UncommonEnums.il new file mode 100644 index 00000000000000..a3bd3874ff1000 --- /dev/null +++ b/src/tests/JIT/opt/Devirtualization/UncommonEnums.il @@ -0,0 +1,42 @@ +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +.assembly extern System.Runtime { .publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) } + +.assembly UncommonEnums { } + +.class public auto ansi sealed CharEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname char value__ +} // end of class CharEnum + +.class public auto ansi sealed BoolEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname bool value__ +} // end of class BoolEnum + +.class public auto ansi sealed FloatEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float32 value__ +} // end of class FloatEnum + +.class public auto ansi sealed DoubleEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname float64 value__ +} // end of class DoubleEnum + +.class public auto ansi sealed IntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native int value__ +} // end of class IntPtrEnum + +.class public auto ansi sealed UIntPtrEnum + extends [System.Runtime]System.Enum +{ + .field public specialname rtspecialname native uint value__ +} // end of class UIntPtrEnum diff --git a/src/tests/JIT/opt/Devirtualization/UncommonEnums.ilproj b/src/tests/JIT/opt/Devirtualization/UncommonEnums.ilproj new file mode 100644 index 00000000000000..05fbf28a4e307c --- /dev/null +++ b/src/tests/JIT/opt/Devirtualization/UncommonEnums.ilproj @@ -0,0 +1,11 @@ + + + Library + true + BuildOnly + false + + + + + From 70883363cb2178462f3bcc5abe8c7402f69b2886 Mon Sep 17 00:00:00 2001 From: petris Date: Sun, 25 Jun 2023 23:54:49 +0200 Subject: [PATCH 10/44] Add missed changes --- src/coreclr/vm/jitinterface.cpp | 6 ------ src/mono/mono/mini/mini.c | 2 +- 2 files changed, 1 insertion(+), 7 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index fecfec31298302..5904018fff180f 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8790,12 +8790,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // And in compile.cpp's SpecializeEqualityComparer TypeHandle elemTypeHnd(elemType); - // Special case for byte - if (elemTypeHnd.AsMethodTable()->HasSameTypeDefAs(CoreLibBinder::GetClass(CLASS__ELEMENT_TYPE_U1))) - { - return CORINFO_CLASS_HANDLE(CoreLibBinder::GetClass(CLASS__BYTE_EQUALITYCOMPARER)); - } - // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer // diff --git a/src/mono/mono/mini/mini.c b/src/mono/mono/mini/mini.c index 97eea8e486940a..76e7e5612f519a 100644 --- a/src/mono/mono/mini/mini.c +++ b/src/mono/mono/mini/mini.c @@ -4301,7 +4301,7 @@ mini_handle_call_res_devirt (MonoMethod *cmethod) // EqualityComparer.Default returns specific types depending on T // FIXME: Special case more types: byte, string, nullable, enum ? - if (mono_class_is_assignable_from_internal (inst, mono_class_from_mono_type_internal (param_type)) && param_type->type != MONO_TYPE_U1 && param_type->type != MONO_TYPE_STRING) { + if (mono_class_is_assignable_from_internal (inst, mono_class_from_mono_type_internal (param_type)) && param_type->type != MONO_TYPE_STRING) { MonoClass *gcomparer_inst; memset (&ctx, 0, sizeof (ctx)); From 0c0c84dbbeacbc2179c31f7db0b87e39990cd340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Mon, 26 Jun 2023 00:06:54 +0200 Subject: [PATCH 11/44] Update ComparerIntrinsics.cs --- .../tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs index 2c966d16291aca..95a29ae04fc181 100644 --- a/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs +++ b/src/coreclr/tools/Common/TypeSystem/IL/Stubs/ComparerIntrinsics.cs @@ -75,7 +75,7 @@ private static MethodIL EmitComparerAndEqualityComparerCreateCommon(MethodDesc m /// Gets the comparer type that is suitable to compare instances of /// or null if such comparer cannot be determined at compile time. /// - private static TypeDesc GetComparerForType(TypeDesc type, string flavor, string interfaceName) + private static InstantiatedType GetComparerForType(TypeDesc type, string flavor, string interfaceName) { TypeSystemContext context = type.Context; From c516e7f16896dcff18fc8b429cfe0c3e03c74cad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Mon, 26 Jun 2023 00:54:23 +0200 Subject: [PATCH 12/44] Update Comparer_get_Default.csproj --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj index 4659c691ffe6d0..687f3d8b5c532e 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.csproj @@ -6,6 +6,6 @@ - + From d8195e6ab21e6ec503cba7ea5dbc2e51f87664a9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Mon, 26 Jun 2023 18:03:14 +0200 Subject: [PATCH 13/44] Workaround roslyn bug --- .../Devirtualization/Comparer_get_Default.cs | 31 ++++++++++++------- 1 file changed, 19 insertions(+), 12 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index aca0d7a9ec309b..251ba0c12ffb02 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -135,6 +135,9 @@ private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) AssertThrows(() => Comparer.Default.Compare(a, b)); } + private static void Compare_Double_Enum(DoubleEnum a, DoubleEnum b) => + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + private static void Compare_Generic_Enum(TEnum a, TEnum b) where TEnum : Enum => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); @@ -261,28 +264,32 @@ public static int TestEntryPoint() Compare_Struct1_Nullable(null, null); Compare_Struct2_Nullable(null, null); - var enumCharA = Unsafe.As(ref a); - var enumCharB = Unsafe.As(ref b); + // workaround for: https://github.com/dotnet/roslyn/issues/68770 + static T Bitcast(long l) => Unsafe.As(ref l); + + var enumCharA = Bitcast(a); + var enumCharB = Bitcast(b); Compare_Generic_Enum(enumCharA, enumCharB); - var enumBoolA = Unsafe.As(ref a); - var enumBoolB = Unsafe.As(ref b); + var enumBoolA = Bitcast(a); + var enumBoolB = Bitcast(b); Compare_Generic_Enum(enumBoolA, enumBoolB); - var enumFloatA = Unsafe.As(ref a); - var enumFloatB = Unsafe.As(ref b); + var enumFloatA = Bitcast(a); + var enumFloatB = Bitcast(b); Compare_Generic_Enum(enumFloatA, enumFloatB); - var enumDoubleA = Unsafe.As(ref a); - var enumDoubleB = Unsafe.As(ref b); + var enumDoubleA = Bitcast(a); + var enumDoubleB = Bitcast(b); Compare_Generic_Enum(enumDoubleA, enumDoubleB); + Compare_Double_Enum(enumDoubleA, enumDoubleB); - var enumIntPtrA = Unsafe.As(ref a); - var enumIntPtrB = Unsafe.As(ref b); + var enumIntPtrA = Bitcast(a); + var enumIntPtrB = Bitcast(b); Compare_Generic_Enum(enumIntPtrA, enumIntPtrB); - var enumUIntPtrA = Unsafe.As(ref a); - var enumUIntPtrB = Unsafe.As(ref b); + var enumUIntPtrA = Bitcast(a); + var enumUIntPtrB = Bitcast(b); Compare_Generic_Enum(enumUIntPtrA, enumUIntPtrB); } } From f8249c781c2bb0315f13eea8878233c68930b639 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Mon, 26 Jun 2023 19:38:19 +0200 Subject: [PATCH 14/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 251ba0c12ffb02..f91dc6198ed1b8 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -121,16 +121,16 @@ private static void Compare_Struct2(Struct2 a, Struct2 b) => AssertThrows(() => Comparer.Default.Compare(a, b)); private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => - AssertEquals(((IComparable)a).CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(((IComparable)a)?.CompareTo(b) ?? (b.IsNull ? 0 : -1), Comparer.Default.Compare(a, b)); private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { if (a.HasValue && b.HasValue) AssertEquals(0, Comparer.Default.Compare(a, b)); else if (a.HasValue) - AssertEquals(-1, Comparer.Default.Compare(a, b)); - else if (b.HasValue) AssertEquals(1, Comparer.Default.Compare(a, b)); + else if (b.HasValue) + AssertEquals(-1, Comparer.Default.Compare(a, b)); else AssertThrows(() => Comparer.Default.Compare(a, b)); } From 4d1d88f805bd3859d8819f6a530fad066201001b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 01:42:23 +0200 Subject: [PATCH 15/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index f91dc6198ed1b8..45b2ba309f9f0f 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -121,7 +121,7 @@ private static void Compare_Struct2(Struct2 a, Struct2 b) => AssertThrows(() => Comparer.Default.Compare(a, b)); private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => - AssertEquals(((IComparable)a)?.CompareTo(b) ?? (b.IsNull ? 0 : -1), Comparer.Default.Compare(a, b)); + AssertEquals(((IComparable)a)?.CompareTo(b) ?? (b.HasValue ? -1 : 0), Comparer.Default.Compare(a, b)); private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { From 5ab501a1bb23506852fcd8f4712db4197789c1de Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 14:59:23 +0200 Subject: [PATCH 16/44] Update Comparer_get_Default.cs --- .../JIT/opt/Devirtualization/Comparer_get_Default.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 45b2ba309f9f0f..f59218fde242b8 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -125,12 +125,12 @@ private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { - if (a.HasValue && b.HasValue) + if (!a.HasValue && !b.HasValue) AssertEquals(0, Comparer.Default.Compare(a, b)); - else if (a.HasValue) - AssertEquals(1, Comparer.Default.Compare(a, b)); - else if (b.HasValue) + else if (!a.HasValue) AssertEquals(-1, Comparer.Default.Compare(a, b)); + else if (!b.HasValue) + AssertEquals(1, Comparer.Default.Compare(a, b)); else AssertThrows(() => Comparer.Default.Compare(a, b)); } @@ -398,7 +398,7 @@ public struct Struct1 : IComparable public long b; public int CompareTo(object obj) { - return b.CompareTo(((Struct1) obj).b); + return obj is Struct1 str ? b.CompareTo(str.b) : 1; } } From 6c45b7edd2907c47d32cd2baf7b9307cd3982370 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 17:32:05 +0200 Subject: [PATCH 17/44] Update Comparer_get_Default.cs --- .../Devirtualization/Comparer_get_Default.cs | 60 +++++++++---------- 1 file changed, 30 insertions(+), 30 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index f59218fde242b8..a175f09c9a19cf 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -12,11 +12,11 @@ public class Program { private static int s_ReturnCode = 100; - private static void AssertEquals(T expected, T actual, [CallerLineNumber] int line = 0) + private static void AssertEquals(T expected, T actual, string values = "", [CallerLineNumber] int line = 0) { if (!expected.Equals(actual)) { - Console.WriteLine($"{expected} != {actual}, L{line}"); + Console.WriteLine($"{values}{expected} != {actual}, L{line}"); s_ReturnCode++; } } @@ -39,58 +39,58 @@ private static void AssertThrows(Action action, [CallerLineNumber] i } private static void Compare_Boolean(Boolean a, Boolean b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Byte(Byte a, Byte b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_SByte(SByte a, SByte b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Char(Char a, Char b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_UInt16(UInt16 a, UInt16 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Int16(Int16 a, Int16 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_UInt32(UInt32 a, UInt32 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Int32(Int32 a, Int32 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Int64(Int64 a, Int64 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_UInt64(UInt64 a, UInt64 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_IntPtr(IntPtr a, IntPtr b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_UIntPtr(UIntPtr a, UIntPtr b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_nint(nint a, nint b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_nuint(nuint a, nuint b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Enum_Int32(MethodImplOptions a, MethodImplOptions b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)), $"({a}; {b}): "; private static void Compare_Enum_Byte(Enum_byte a, Enum_byte b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_String(String a, String b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_DateTime(DateTime a, DateTime b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Int32_Nullable(long? a, long? b) { @@ -100,7 +100,7 @@ private static void Compare_Int32_Nullable(long? a, long? b) expected = b.HasValue ? a.Value.CompareTo(b.Value) : 1; else expected = b.HasValue ? -1 : 0; - AssertEquals(expected, actual); + AssertEquals(expected, actual, $"({a}; {b}): "); } private static void Compare_Enum_Int32_Nullable(MethodImplOptions? a, MethodImplOptions? b) @@ -111,35 +111,35 @@ private static void Compare_Enum_Int32_Nullable(MethodImplOptions? a, MethodImpl expected = b.HasValue ? a.Value.CompareTo(b.Value) : 1; else expected = b.HasValue ? -1 : 0; - AssertEquals(expected, actual); + AssertEquals(expected, actual, $"({a}; {b}): "); } private static void Compare_Struct1(Struct1 a, Struct1 b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Struct2(Struct2 a, Struct2 b) => - AssertThrows(() => Comparer.Default.Compare(a, b)); + AssertThrows(() => Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Struct1_Nullable(Struct1? a, Struct1? b) => - AssertEquals(((IComparable)a)?.CompareTo(b) ?? (b.HasValue ? -1 : 0), Comparer.Default.Compare(a, b)); + AssertEquals(((IComparable)a)?.CompareTo(b) ?? (b.HasValue ? -1 : 0), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) { if (!a.HasValue && !b.HasValue) - AssertEquals(0, Comparer.Default.Compare(a, b)); + AssertEquals(0, Comparer.Default.Compare(a, b), $"({a}; {b}): "); else if (!a.HasValue) - AssertEquals(-1, Comparer.Default.Compare(a, b)); + AssertEquals(-1, Comparer.Default.Compare(a, b), $"({a}; {b}): "); else if (!b.HasValue) - AssertEquals(1, Comparer.Default.Compare(a, b)); + AssertEquals(1, Comparer.Default.Compare(a, b), $"({a}; {b}): "); else AssertThrows(() => Comparer.Default.Compare(a, b)); } private static void Compare_Double_Enum(DoubleEnum a, DoubleEnum b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Generic_Enum(TEnum a, TEnum b) where TEnum : Enum => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); [Fact] public static int TestEntryPoint() From 40eab70666d238dc0ae00d069606e4d821250a11 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 18:17:14 +0200 Subject: [PATCH 18/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index a175f09c9a19cf..d3dbc2ec8528de 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -81,7 +81,7 @@ private static void Compare_nuint(nuint a, nuint b) => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Enum_Int32(MethodImplOptions a, MethodImplOptions b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b)), $"({a}; {b}): "; + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); private static void Compare_Enum_Byte(Enum_byte a, Enum_byte b) => AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); From ff59591b60b6bbcdfad9bcd702e41defaeafaec5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 20:50:39 +0200 Subject: [PATCH 19/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index d3dbc2ec8528de..b75ef16156b48b 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -21,19 +21,19 @@ private static void AssertEquals(T expected, T actual, string values = "", [C } } - private static void AssertThrows(Action action, [CallerLineNumber] int line = 0) where TException : Exception + private static void AssertThrows(Action action, string values = "", [CallerLineNumber] int line = 0) where TException : Exception { try { action(); - Console.WriteLine($"no {typeof(TException).FullName}, L{line}"); + Console.WriteLine($"{values}no {typeof(TException).FullName}, L{line}"); s_ReturnCode++; } catch (Exception ex) { if (ex.GetType() == typeof(TException)) return; - Console.WriteLine($"{ex.GetType().FullName} != {typeof(TException).FullName}, L{line}"); + Console.WriteLine($"{values}{ex.GetType().FullName} != {typeof(TException).FullName}, L{line}"); s_ReturnCode++; } } From 1f2b4aa8a5e64e546da4cb2921b53a5fddd09db1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 22:31:43 +0200 Subject: [PATCH 20/44] Update Comparer_get_Default.cs --- .../JIT/opt/Devirtualization/Comparer_get_Default.cs | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index b75ef16156b48b..66b8de13215f57 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -135,11 +135,18 @@ private static void Compare_Struct2_Nullable(Struct2? a, Struct2? b) AssertThrows(() => Comparer.Default.Compare(a, b)); } + private static string PrintBits(T value) + { + ulong l = 0; + Unsafe.As(ref l) = value; + return l.ToString(); + } + private static void Compare_Double_Enum(DoubleEnum a, DoubleEnum b) => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({PrintBits(a)}; {PrintBits(b)}): "); private static void Compare_Generic_Enum(TEnum a, TEnum b) where TEnum : Enum => - AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({a}; {b}): "); + AssertEquals(a.CompareTo(b), Comparer.Default.Compare(a, b), $"({PrintBits(a)}; {PrintBits(b)}): "); [Fact] public static int TestEntryPoint() From d0627bf0c0f169df946df25377ba5b6de8eba4cc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 27 Jun 2023 22:35:13 +0200 Subject: [PATCH 21/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 66b8de13215f57..2b865d915df4ac 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -139,7 +139,7 @@ private static string PrintBits(T value) { ulong l = 0; Unsafe.As(ref l) = value; - return l.ToString(); + return $"({typeof(T).FullName}){l}"; } private static void Compare_Double_Enum(DoubleEnum a, DoubleEnum b) => From ba2e5cb4b34ddf1bcb7d9beb613e0e1759cb9128 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:13:51 +0200 Subject: [PATCH 22/44] Update intrinsics.c --- src/mono/mono/mini/intrinsics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index 76dbabbd4018d9..e22a37ef4c6310 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -675,7 +675,7 @@ emit_jit_helpers_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSi if (mini_is_gsharedvt_variable_type (t)) return NULL; - gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8); + gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8 || (TARGET_SIZEOF_VOID_P == 8 && (t->type == MONO_TYPE_I || t->type == MONO_TYPE_U))); gboolean is_unsigned = (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_U2 || t->type == MONO_TYPE_U4 || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U); int cmp_op, ceq_op, cgt_op, clt_op; From 6bdbee224f6834cea4f772d287abc055b871acd3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 28 Jun 2023 01:14:35 +0200 Subject: [PATCH 23/44] Update transform.c --- src/mono/mono/mini/interp/transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 9089733a476750..fa905d1420d207 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2526,7 +2526,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoType *t = ctx->method_inst->type_argv [0]; t = mini_get_underlying_type (t); - gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8); + gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8 || (TARGET_SIZEOF_VOID_P == 8 && (t->type == MONO_TYPE_I || t->type == MONO_TYPE_U))); gboolean is_unsigned = (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_U2 || t->type == MONO_TYPE_U4 || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U); gboolean is_compareto = strcmp (tm, "EnumCompareTo") == 0; From 1d14835f1854f1a236a990adaf79aa6d9c70628e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 28 Jun 2023 18:04:10 +0200 Subject: [PATCH 24/44] Update intrinsics.c --- src/mono/mono/mini/intrinsics.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/intrinsics.c b/src/mono/mono/mini/intrinsics.c index e22a37ef4c6310..68dc78bd22bc4d 100644 --- a/src/mono/mono/mini/intrinsics.c +++ b/src/mono/mono/mini/intrinsics.c @@ -672,7 +672,7 @@ emit_jit_helpers_intrinsics (MonoCompile *cfg, MonoMethod *cmethod, MonoMethodSi t = ctx->method_inst->type_argv [0]; t = mini_get_underlying_type (t); - if (mini_is_gsharedvt_variable_type (t)) + if (mini_is_gsharedvt_variable_type (t) || t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8) return NULL; gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8 || (TARGET_SIZEOF_VOID_P == 8 && (t->type == MONO_TYPE_I || t->type == MONO_TYPE_U))); From f4009d74f2a23240bf63c877de870df32cbe49cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 28 Jun 2023 18:05:35 +0200 Subject: [PATCH 25/44] Update transform.c --- src/mono/mono/mini/interp/transform.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index fa905d1420d207..e8f4e6efb92a8b 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2526,6 +2526,9 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoType *t = ctx->method_inst->type_argv [0]; t = mini_get_underlying_type (t); + if (t->type == MONO_TYPE_BOOLEAN || t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8) + return FALSE; + gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8 || (TARGET_SIZEOF_VOID_P == 8 && (t->type == MONO_TYPE_I || t->type == MONO_TYPE_U))); gboolean is_unsigned = (t->type == MONO_TYPE_U1 || t->type == MONO_TYPE_U2 || t->type == MONO_TYPE_U4 || t->type == MONO_TYPE_U8 || t->type == MONO_TYPE_U); From 6fdb5c9548d52a354fd61df2ecb7f793a1e805c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 28 Jun 2023 18:08:24 +0200 Subject: [PATCH 26/44] Update JitHelpers.cs --- .../src/System/Runtime/CompilerServices/JitHelpers.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs index 40d30c6001599d..c60d5f6f733b34 100644 --- a/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs +++ b/src/mono/System.Private.CoreLib/src/System/Runtime/CompilerServices/JitHelpers.cs @@ -5,13 +5,11 @@ namespace System.Runtime.CompilerServices { internal static class JitHelpers { -#pragma warning disable IDE0060 [Intrinsic] - public static bool EnumEquals(T x, T y) where T : struct, Enum => throw new NotImplementedException(); + public static bool EnumEquals(T x, T y) where T : struct, Enum => x.Equals(y); [Intrinsic] - public static int EnumCompareTo(T x, T y) where T : struct, Enum => throw new NotImplementedException(); -#pragma warning restore IDE0060 + public static int EnumCompareTo(T x, T y) where T : struct, Enum => x.CompareTo(y); [Intrinsic] internal static void DisableInline () => throw new NotImplementedException(); From 7659053ab1738054fda41a518c0799dc0896097d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Thu, 29 Jun 2023 18:49:12 +0200 Subject: [PATCH 27/44] Update transform.c --- src/mono/mono/mini/interp/transform.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/mono/mono/mini/interp/transform.c b/src/mono/mono/mini/interp/transform.c index 182cf18e8e8af5..d36e400316a359 100644 --- a/src/mono/mono/mini/interp/transform.c +++ b/src/mono/mono/mini/interp/transform.c @@ -2536,7 +2536,7 @@ interp_handle_intrinsics (TransformData *td, MonoMethod *target_method, MonoClas MonoType *t = ctx->method_inst->type_argv [0]; t = mini_get_underlying_type (t); - if (t->type == MONO_TYPE_BOOLEAN || t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8) + if (t->type == MONO_TYPE_R4 || t->type == MONO_TYPE_R8) return FALSE; gboolean is_i8 = (t->type == MONO_TYPE_I8 || t->type == MONO_TYPE_U8 || (TARGET_SIZEOF_VOID_P == 8 && (t->type == MONO_TYPE_I || t->type == MONO_TYPE_U))); From 8ec024f312ce341a2231e0b6840dacda0f463505 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 03:00:05 +0200 Subject: [PATCH 28/44] Update compiler.h --- src/coreclr/jit/compiler.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/compiler.h b/src/coreclr/jit/compiler.h index c90fab906aa2c3..806c2f559dd5c7 100644 --- a/src/coreclr/jit/compiler.h +++ b/src/coreclr/jit/compiler.h @@ -3871,7 +3871,7 @@ class Compiler CORINFO_CALL_INFO* callInfo, IL_OFFSET rawILOffset); - CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(GenTreeCall* call, bool* pIsExact); + CORINFO_CLASS_HANDLE impGetSpecialIntrinsicExactReturnType(GenTreeCall* call); GenTree* impFixupCallStructReturn(GenTreeCall* call, CORINFO_CLASS_HANDLE retClsHnd); From f5a9c18270dfd76171f28f647c86d2ffb6906f7a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 03:01:07 +0200 Subject: [PATCH 29/44] Update gentree.cpp --- src/coreclr/jit/gentree.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/coreclr/jit/gentree.cpp b/src/coreclr/jit/gentree.cpp index b23df9c0e8e120..deee04b0a3d7f9 100644 --- a/src/coreclr/jit/gentree.cpp +++ b/src/coreclr/jit/gentree.cpp @@ -17948,12 +17948,11 @@ CORINFO_CLASS_HANDLE Compiler::gtGetClassHandle(GenTree* tree, bool* pIsExact, b break; } - bool isExact = false; - CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call, &isExact); + CORINFO_CLASS_HANDLE specialObjClass = impGetSpecialIntrinsicExactReturnType(call); if (specialObjClass != nullptr) { objClass = specialObjClass; - *pIsExact = isExact; + *pIsExact = true; *pIsNonNull = true; break; } From c33e1de9558265444d771beed2c26727b476f787 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 03:01:57 +0200 Subject: [PATCH 30/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index b39f1fe5dd955e..567c34a2044dd8 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7531,18 +7531,16 @@ Compiler::GDVProbeType Compiler::compClassifyGDVProbeType(GenTreeCall* call) // // Arguments: // methodHnd -- handle for the special intrinsic method -// pIsExact -- returns whether the type is exact // // Returns: // Exact class handle returned by the intrinsic call, if known. // Nullptr if not known, or not likely to lead to beneficial optimization. -CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall* call, bool* pIsExact) +CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall* call) { CORINFO_METHOD_HANDLE methodHnd = call->gtCallMethHnd; JITDUMP("Special intrinsic: looking for exact type returned by %s\n", eeGetMethodFullName(methodHnd)); CORINFO_CLASS_HANDLE result = nullptr; - *pIsExact = false; // See what intrinsic we have... const NamedIntrinsic ni = lookupNamedIntrinsic(methodHnd); @@ -7593,7 +7591,6 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall assert(ni == NI_System_Collections_Generic_Comparer_get_Default); result = info.compCompHnd->getDefaultComparerClass(typeHnd); } - *pIsExact = result != nullptr; JITDUMP("Special intrinsic for type %s: return type is %s\n", eeGetClassName(typeHnd), result != nullptr ? eeGetClassName(result) : "unknown"); } From 588d8843f1cbeb9ce164870eb3f3c42f0f950084 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 18:10:15 +0200 Subject: [PATCH 31/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 567c34a2044dd8..43da4ce15be01b 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7558,10 +7558,9 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall // Lookup can incorrect when we have __Canon as it won't appear // to implement any interface types. - const DWORD typeAttribs = info.compCompHnd->getClassAttribs(typeHnd); - bool isShared = ((typeAttribs & CORINFO_FLG_SHAREDINST) != 0); + bool isCanon = ((info.compCompHnd->getClassAttribs(typeHnd) & (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); - if (isShared) + if (isCanon) { CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); if (instParam != nullptr) @@ -7571,16 +7570,16 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall if (hClass != NO_CLASS_HANDLE) { hClass = getTypeInstantiationArgument(hClass, 0); - if ((info.compCompHnd->getClassAttribs(hClass) & CORINFO_FLG_SHAREDINST) == 0) + isCanon = ((info.compCompHnd->getClassAttribs(hClass) & (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); + if (!isCanon) { typeHnd = hClass; - isShared = false; } } } } - if (!isShared) + if (!isCanon) { if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default) { From a64df29a738dd04142bbb8919b6fdc9526c927d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 18:55:55 +0200 Subject: [PATCH 32/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 43da4ce15be01b..3674f55d41f447 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7558,7 +7558,8 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall // Lookup can incorrect when we have __Canon as it won't appear // to implement any interface types. - bool isCanon = ((info.compCompHnd->getClassAttribs(typeHnd) & (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); + bool isCanon = ((info.compCompHnd->getClassAttribs(typeHnd) & + (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); if (isCanon) { @@ -7569,11 +7570,12 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(instParam->GetNode()); if (hClass != NO_CLASS_HANDLE) { - hClass = getTypeInstantiationArgument(hClass, 0); - isCanon = ((info.compCompHnd->getClassAttribs(hClass) & (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); + hClass = getTypeInstantiationArgument(hClass, 0); + isCanon = ((info.compCompHnd->getClassAttribs(hClass) & + (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); if (!isCanon) { - typeHnd = hClass; + typeHnd = hClass; } } } From fa682a242876a3e59c45b551895572860f1d91d0 Mon Sep 17 00:00:00 2001 From: petris Date: Fri, 30 Jun 2023 21:06:58 +0200 Subject: [PATCH 33/44] Move Canon checking to VM --- src/coreclr/jit/importercalls.cpp | 49 ++++++++++++------------------- src/coreclr/vm/jitinterface.cpp | 5 ++++ 2 files changed, 23 insertions(+), 31 deletions(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index 3674f55d41f447..f661e085d15f7f 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7553,45 +7553,33 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall CORINFO_SIG_INFO sig; info.compCompHnd->getMethodSig(methodHnd, &sig); assert(sig.sigInst.classInstCount == 1); + CORINFO_CLASS_HANDLE typeHnd = sig.sigInst.classInst[0]; assert(typeHnd != nullptr); - // Lookup can incorrect when we have __Canon as it won't appear - // to implement any interface types. - bool isCanon = ((info.compCompHnd->getClassAttribs(typeHnd) & - (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); - - if (isCanon) + CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); + if (instParam != nullptr) { - CallArg* instParam = call->gtArgs.FindWellKnownArg(WellKnownArg::InstParam); - if (instParam != nullptr) + assert(instParam->GetNext() == nullptr); + CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(instParam->GetNode()); + if (hClass != NO_CLASS_HANDLE) { - assert(instParam->GetNext() == nullptr); - CORINFO_CLASS_HANDLE hClass = gtGetHelperArgClassHandle(instParam->GetNode()); - if (hClass != NO_CLASS_HANDLE) - { - hClass = getTypeInstantiationArgument(hClass, 0); - isCanon = ((info.compCompHnd->getClassAttribs(hClass) & - (CORINFO_FLG_SHAREDINST | CORINFO_FLG_FINAL)) == CORINFO_FLG_SHAREDINST); - if (!isCanon) - { - typeHnd = hClass; - } - } + typeHnd = getTypeInstantiationArgument(hClass, 0); } } - if (!isCanon) + if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default) + { + result = info.compCompHnd->getDefaultEqualityComparerClass(typeHnd); + } + else + { + assert(ni == NI_System_Collections_Generic_Comparer_get_Default); + result = info.compCompHnd->getDefaultComparerClass(typeHnd); + } + + if (result != NO_CLASS_HANDLE) { - if (ni == NI_System_Collections_Generic_EqualityComparer_get_Default) - { - result = info.compCompHnd->getDefaultEqualityComparerClass(typeHnd); - } - else - { - assert(ni == NI_System_Collections_Generic_Comparer_get_Default); - result = info.compCompHnd->getDefaultComparerClass(typeHnd); - } JITDUMP("Special intrinsic for type %s: return type is %s\n", eeGetClassName(typeHnd), result != nullptr ? eeGetClassName(result) : "unknown"); } @@ -7599,7 +7587,6 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall { JITDUMP("Special intrinsic for type %s: type shared, so deferring opt\n", eeGetClassName(typeHnd)); } - break; } diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index aa04949f20cd6f..c409882ca5ec0a 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8786,6 +8786,11 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE TypeHandle elemTypeHnd(elemType); + if (elemTypeHnd == TypeHandle(g_pCanonMethodTableClass)) + { + return NULL; + } + // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer // From 859a25d162cac0a22131085424dcb0b9d89f3a46 Mon Sep 17 00:00:00 2001 From: petris Date: Fri, 30 Jun 2023 21:08:30 +0200 Subject: [PATCH 34/44] Check in EqualityComparer too --- src/coreclr/vm/jitinterface.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index c409882ca5ec0a..fad63bc6ac9225 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8857,6 +8857,11 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // And in compile.cpp's SpecializeEqualityComparer TypeHandle elemTypeHnd(elemType); + if (elemTypeHnd == TypeHandle(g_pCanonMethodTableClass)) + { + return NULL; + } + // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer // From 45ec76dfa97240c4715d2e1e601332c01d572a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 21:19:21 +0200 Subject: [PATCH 35/44] Update Comparer_get_Default.cs --- .../Devirtualization/Comparer_get_Default.cs | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 2b865d915df4ac..ceaebd4a590389 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -341,6 +341,11 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.EnumComparer`1[UIntPtrEnum]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct1]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.Int32]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.String]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", Comparer.Default.GetType().ToString()); @@ -352,6 +357,10 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableComparer`1[UIntPtrEnum]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct1]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[Struct2]", Comparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.Int32]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.String]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); @@ -366,6 +375,11 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.EnumEqualityComparer`1[UIntPtrEnum]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Runtime.CompilerServices.MethodImplOptions]", EqualityComparer.Default.GetType().ToString()); @@ -377,6 +391,10 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[UIntPtrEnum]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct1]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); } private static int GetHashCodeTests() { @@ -414,3 +432,11 @@ public struct Struct2 public long a; public long b; } + +public struct StructGeneric : IEquatable>, IComparable> +{ + public T t; + + public bool Equals(StructGeneric s) => EqualityComparer.Default.Equals(t, s.t); + public int CompareTo(StructGeneric s) => Comparer.Default.Compare(t, s.t); +} From 1c790522e65430f47ee5f87baf3730ecdcb4aec7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 21:36:35 +0200 Subject: [PATCH 36/44] Update src/coreclr/jit/importercalls.cpp Co-authored-by: Jan Kotas --- src/coreclr/jit/importercalls.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index f661e085d15f7f..f2e5faa75bfa91 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7585,7 +7585,7 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall } else { - JITDUMP("Special intrinsic for type %s: type shared, so deferring opt\n", eeGetClassName(typeHnd)); + JITDUMP("Special intrinsic for type %s: type undetermined, so deferring opt\n", eeGetClassName(typeHnd)); } break; } From d0ad2dd01d4967145956072716eb4cca21bc9cf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 21:50:09 +0200 Subject: [PATCH 37/44] Update Comparer_get_Default.cs --- .../Devirtualization/Comparer_get_Default.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index ceaebd4a590389..c6907050ace140 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -343,8 +343,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.Int32]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.String]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericComparer`1[StructGenericString`1[System.String]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.Object]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); @@ -359,8 +363,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.Int32]]", Comparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.String]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.String]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.Object]]", Comparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); @@ -377,8 +385,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); @@ -393,8 +405,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>?>.Default.GetType().ToString()); } private static int GetHashCodeTests() { @@ -440,3 +456,11 @@ public struct StructGeneric : IEquatable>, IComparable s) => EqualityComparer.Default.Equals(t, s.t); public int CompareTo(StructGeneric s) => Comparer.Default.Compare(t, s.t); } + +public struct StructGenericString : IEquatable, IComparable +{ + public T t; + + public bool Equals(string s) => s == t?.ToString(); + public int CompareTo(string s) => Comparer.Default.Compare(t?.ToString(), s); +} From 8471b2134eef4e0d5ad2843b07915a719ce85360 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 22:00:39 +0200 Subject: [PATCH 38/44] Update Comparer_get_Default.cs --- src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index c6907050ace140..b2589be67808ab 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -343,7 +343,7 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.Int32]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.String]]", Comparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.GenericComparer`1[StructGenericString`1[System.String]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.String]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.Object]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); @@ -385,7 +385,7 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); From 1999819a12e653160323c71478993295dd998951 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 22:15:47 +0200 Subject: [PATCH 39/44] Update importercalls.cpp --- src/coreclr/jit/importercalls.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/coreclr/jit/importercalls.cpp b/src/coreclr/jit/importercalls.cpp index f2e5faa75bfa91..b4ea24fae523f6 100644 --- a/src/coreclr/jit/importercalls.cpp +++ b/src/coreclr/jit/importercalls.cpp @@ -7585,7 +7585,8 @@ CORINFO_CLASS_HANDLE Compiler::impGetSpecialIntrinsicExactReturnType(GenTreeCall } else { - JITDUMP("Special intrinsic for type %s: type undetermined, so deferring opt\n", eeGetClassName(typeHnd)); + JITDUMP("Special intrinsic for type %s: type undetermined, so deferring opt\n", + eeGetClassName(typeHnd)); } break; } From 35ee0a292552b092f0f3d119e97c15aad3ad3fd5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Fri, 30 Jun 2023 23:38:56 +0200 Subject: [PATCH 40/44] Update Comparer_get_Default.cs --- .../opt/Devirtualization/Comparer_get_Default.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index b2589be67808ab..94f68bf03334f5 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -385,12 +385,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); @@ -405,12 +405,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[Struct2]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.Int32]]", EqualityComparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.String]]", EqualityComparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[System.Object]]", EqualityComparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", EqualityComparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", EqualityComparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableEqualityComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", EqualityComparer>?>.Default.GetType().ToString()); } private static int GetHashCodeTests() { From 7c902b4df8f6c0b9ca192e643466f48d842eb840 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Sat, 1 Jul 2023 00:57:50 +0200 Subject: [PATCH 41/44] Update Comparer_get_Default.cs --- .../opt/Devirtualization/Comparer_get_Default.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 94f68bf03334f5..3d515b6fb713e3 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -343,12 +343,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.ObjectComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.Int32]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[System.String]]", Comparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.String]]", Comparer>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.Object]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.String]]", Comparer>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[System.Object]]", Comparer>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.ObjectComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[System.Int32]", Comparer.Default.GetType().ToString()); @@ -363,12 +363,12 @@ private static void GetTypeTests() AssertEquals("System.Collections.Generic.NullableComparer`1[Struct2]", Comparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.Int32]]", Comparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[System.String]]", Comparer?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.String]]", Comparer?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.Object]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.String]]", Comparer?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[System.Object]]", Comparer?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.Int32]]]", Comparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.NullableComparer`1[StructGeneric`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); - AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.String]]]", Comparer>?>.Default.GetType().ToString()); + AssertEquals("System.Collections.Generic.NullableComparer`1[StructGenericString`1[StructGeneric`1[System.Object]]]", Comparer>?>.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Byte]", EqualityComparer.Default.GetType().ToString()); AssertEquals("System.Collections.Generic.GenericEqualityComparer`1[System.Int32]", EqualityComparer.Default.GetType().ToString()); From fc21b4f51c93c6d21b34c102dd258e4d9cacb002 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Tue, 4 Jul 2023 00:20:56 +0200 Subject: [PATCH 42/44] Update jitinterface.cpp --- src/coreclr/vm/jitinterface.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index f2770bef84e87d..efde4bcafd7ceb 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8786,11 +8786,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE TypeHandle elemTypeHnd(elemType); - if (elemTypeHnd == TypeHandle(g_pCanonMethodTableClass)) - { - return NULL; - } - // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer // @@ -8819,6 +8814,11 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } + if (elemTypeHnd.IsCanonicalSubtype()) + { + return NULL; + } + // Default case TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_COMPARER)).Instantiate(inst); @@ -8857,11 +8857,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // And in compile.cpp's SpecializeEqualityComparer TypeHandle elemTypeHnd(elemType); - if (elemTypeHnd == TypeHandle(g_pCanonMethodTableClass)) - { - return NULL; - } - // Mirrors the logic in BCL's CompareHelpers.CreateDefaultComparer // And in compile.cpp's SpecializeComparer // @@ -8893,6 +8888,11 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); } + if (elemTypeHnd.IsCanonicalSubtype()) + { + return NULL; + } + // Default case TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst); From fff6180f3bdd427323c4f48c51c192fd4f62f46c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 5 Jul 2023 01:08:03 +0200 Subject: [PATCH 43/44] Update jitinterface.cpp --- src/coreclr/vm/jitinterface.cpp | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/coreclr/vm/jitinterface.cpp b/src/coreclr/vm/jitinterface.cpp index efde4bcafd7ceb..8c336989ce0627 100644 --- a/src/coreclr/vm/jitinterface.cpp +++ b/src/coreclr/vm/jitinterface.cpp @@ -8792,13 +8792,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE // We need to find the appropriate instantiation Instantiation inst(&elemTypeHnd, 1); - // If T implements IComparable - if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(inst))) - { - TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_COMPARER)).Instantiate(inst); - return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); - } - // Nullable if (Nullable::IsNullableType(elemTypeHnd)) { @@ -8819,6 +8812,13 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultComparerClassHelper(CORINFO_CLASS_HANDLE return NULL; } + // If T implements IComparable + if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__ICOMPARABLEGENERIC)).Instantiate(inst))) + { + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_COMPARER)).Instantiate(inst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); + } + // Default case TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_COMPARER)).Instantiate(inst); @@ -8863,13 +8863,6 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS // We need to find the appropriate instantiation Instantiation inst(&elemTypeHnd, 1); - // If T implements IEquatable - if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst))) - { - TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst); - return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); - } - // Nullable if (Nullable::IsNullableType(elemTypeHnd)) { @@ -8893,6 +8886,13 @@ CORINFO_CLASS_HANDLE CEEInfo::getDefaultEqualityComparerClassHelper(CORINFO_CLAS return NULL; } + // If T implements IEquatable + if (elemTypeHnd.CanCastTo(TypeHandle(CoreLibBinder::GetClass(CLASS__IEQUATABLEGENERIC)).Instantiate(inst))) + { + TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__GENERIC_EQUALITYCOMPARER)).Instantiate(inst); + return CORINFO_CLASS_HANDLE(resultTh.GetMethodTable()); + } + // Default case TypeHandle resultTh = ((TypeHandle)CoreLibBinder::GetClass(CLASS__OBJECT_EQUALITYCOMPARER)).Instantiate(inst); From 1b1c1e75b60aefabc455c01aa02da92eea9d58a2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Petryka?= <35800402+MichalPetryka@users.noreply.github.com> Date: Wed, 5 Jul 2023 14:13:01 +0200 Subject: [PATCH 44/44] Update Comparer_get_Default.cs --- .../Devirtualization/Comparer_get_Default.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs index 3d515b6fb713e3..1b30afb2b58178 100644 --- a/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs +++ b/src/tests/JIT/opt/Devirtualization/Comparer_get_Default.cs @@ -320,12 +320,24 @@ public static int TestEntryPoint() Compare_Int32_Nullable(-1, null); Compare_Enum_Int32_Nullable(null, null); + GenericsTest(); GetTypeTests(); GetHashCodeTests(); return s_ReturnCode; } + private static void GenericsTest() + { + AssertEquals(true, Test()); + + [MethodImpl(MethodImplOptions.NoInlining)] + static bool Test() + { + return EqualityComparer>.Default.Equals(default, default); + } + } + private static void GetTypeTests() { AssertEquals("System.Collections.Generic.GenericComparer`1[System.Byte]", Comparer.Default.GetType().ToString()); @@ -464,3 +476,8 @@ public struct StructGenericString : IEquatable, IComparable public bool Equals(string s) => s == t?.ToString(); public int CompareTo(string s) => Comparer.Default.Compare(t?.ToString(), s); } + +struct G : IEquatable> +{ + public bool Equals(G x) => false; +}