@@ -261,6 +261,7 @@ type OptimizationSettings =
261261 jitOptUser : bool option
262262 localOptUser : bool option
263263 crossModuleOptUser : bool option
264+ optimizeComparisonLogic : bool
264265 /// size after which we start chopping methods in two, though only at match targets
265266 bigTargetSize : int
266267 /// size after which we start enforcing splitting sub-expressions to new methods, to avoid hitting .NET IL limitations
@@ -278,6 +279,7 @@ type OptimizationSettings =
278279 { abstractBigTargets = false
279280 jitOptUser = None
280281 localOptUser = None
282+ optimizeComparisonLogic = false
281283 /// size after which we start chopping methods in two, though only at match targets
282284 bigTargetSize = 100
283285 /// size after which we start enforcing splitting sub-expressions to new methods, to avoid hitting .NET IL limitations
@@ -2472,7 +2474,34 @@ and DevirtualizeApplication cenv env (vref:ValRef) ty tyargs args m =
24722474 let wrap , args = TakeAddressOfStructArgumentIfNeeded cenv vref ty args m
24732475 let transformedExpr = wrap ( MakeApplicationAndBetaReduce cenv.g ( exprForValRef m vref, vref.Type, ( if isNil tyargs then [] else [ tyargs]), args, m))
24742476 OptimizeExpr cenv env transformedExpr
2475-
2477+
2478+ and DevirtualizeGenericEqualityIntrinsic cenv env receiver arg m =
2479+ let call = mkCall_ IEquatableT_ Equals cenv.g m receiver arg
2480+ OptimizeExpr cenv env call
2481+
2482+ /// Check if a type 'ty' implements 'IEquatable<ty >'
2483+ and IsIEquatableTy cenv m ty =
2484+ let searchTy = mkAppTy cenv.g.system_ GenericIEquatable_ tcref [ ty]
2485+ ExistsInEntireHierarchyOfType ( fun t -> typeEquiv cenv.g t searchTy) cenv.g cenv.amap m AllowMultiIntfInstantiations.Yes ty
2486+
2487+ /// Check if a type 'ty' implements 'IStructuralEquatable'
2488+ and IsIStructuralEquatableTy cenv m ty =
2489+ let searchTy = mkAppTy cenv.g.tcref_ System_ IStructuralEquatable []
2490+ ExistsInEntireHierarchyOfType ( fun t -> typeEquiv cenv.g t searchTy) cenv.g cenv.amap m AllowMultiIntfInstantiations.Yes ty
2491+
2492+ /// Check if a type 'ty' is a structural F# type with default structural equality semantics
2493+ and IsGeneratedHashAndEqualsTy g ty =
2494+ isAnonRecdTy g ty ||
2495+ ( isAppTy g ty &&
2496+ ( let tcref = tcrefOfAppTy g ty
2497+ tcref.GeneratedHashAndEqualsValues.IsSome && tcref.GeneratedHashAndEqualsWithComparerValues.IsSome))
2498+
2499+ /// Check if we can (perhaps optimistically) convert the reduced optimization of 'a = b' to '(a :> IEquatable).Equals(b)'
2500+ and CanOptimizeGenericEqualityIntrinsicToIEquatableEquals cenv m ty =
2501+ IsIEquatableTy cenv m ty &&
2502+ not ( isAnyTupleTy cenv.g ty) &&
2503+ ( IsGeneratedHashAndEqualsTy cenv.g ty || ( cenv.settings.optimizeComparisonLogic && not ( IsIStructuralEquatableTy cenv m ty)))
2504+
24762505and TryDevirtualizeApplication cenv env ( f , tyargs , args , m ) =
24772506 match f, tyargs, args with
24782507
@@ -2529,7 +2558,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) =
25292558 | _ -> None
25302559
25312560 // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericEqualityWithComparer
2532- | Expr.Val( v, _, _), [ ty], _ when CanDevirtualizeApplication cenv v cenv.g.generic _ equality _ per _ inner _ vref ty args && not ( isRefTupleTy cenv.g ty) ->
2561+ | Expr.Val( v, _, _), [ ty], _ when CanDevirtualizeApplication cenv v cenv.g.generic _ equality _ withc _ outer _ vref ty args && not ( isRefTupleTy cenv.g ty) ->
25332562 let tcref , tyargs = StripToNominalTyconRef cenv ty
25342563 match tcref.GeneratedHashAndEqualsWithComparerValues, args with
25352564 | Some (_, _, withcEqualsVal), [ x; y] ->
@@ -2599,7 +2628,7 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) =
25992628 match vref with
26002629 | Some vref -> Some ( DevirtualizeApplication cenv env vref ty tyargs ( mkCallGetGenericPEREqualityComparer cenv.g m :: args) m)
26012630 | None -> None
2602-
2631+
26032632 // Optimize/analyze calls to LanguagePrimitives.HashCompare.GenericComparisonWithComparerIntrinsic for tuple types
26042633 | Expr.Val( v, _, _), [ ty], _ when valRefEq cenv.g v cenv.g.generic_ comparison_ withc_ inner_ vref && isRefTupleTy cenv.g ty ->
26052634 let tyargs = destRefTupleTy cenv.g ty
@@ -2668,6 +2697,9 @@ and TryDevirtualizeApplication cenv env (f, tyargs, args, m) =
26682697 MightMakeCriticalTailcall = false
26692698 Info= UnknownValue})
26702699
2700+ | Expr.Val( v, _, _), [_], [ receiver; arg] when valRefEq cenv.g v cenv.g.generic_ equality_ per_ inner_ vref && CanOptimizeGenericEqualityIntrinsicToIEquatableEquals cenv m ( tyOfExpr cenv.g receiver) ->
2701+ Some( DevirtualizeGenericEqualityIntrinsic cenv env receiver arg m)
2702+
26712703 | _ -> None
26722704
26732705/// Attempt to inline an application of a known value at callsites
0 commit comments