Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support fast tailcalls in R2R #56669

Merged
merged 28 commits into from
Oct 7, 2021
Merged

Conversation

jakobbotsch
Copy link
Member

@jakobbotsch jakobbotsch commented Jul 31, 2021

Implement a delay load helper that supports fast tailcalls on x64. The JIT loads the indirection cell into rax and emits jmp [rax]. The new helper uses the indirection from rax.

Also add support for containing immediate indirs in the tailcalling. We cannot contain any indir since they may need values in registers that have been cleaned up.

ARM64 almost supported this out of the box since there the helper already gets the indirection cell from a register. The only change needed was to properly load the call target.

I also took the JIT GUID update as an opportunity to clean up the mcPackets enum: I have sorted the entries by their actual values and commented out the unused ones.

Partially addresses #5857

@dotnet-issue-labeler dotnet-issue-labeler bot added the area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI label Jul 31, 2021
@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member Author

/azp run runtime-coreclr outerloop

@azure-pipelines
Copy link

Azure Pipelines successfully started running 1 pipeline(s).

@jakobbotsch
Copy link
Member Author

@jkotas
Copy link
Member

jkotas commented Aug 3, 2021

Implement DefType.IsUnsafeValueType

It would be nice to submit this one in separate PR.

@jakobbotsch
Copy link
Member Author

It would be nice to submit this one in separate PR.

Will do. @MichalStrehovsky said there was a 6.0 issue for GS cookies somewhere, but I haven't been able to find it. Can anyone point me to it?

@MichalStrehovsky
Copy link
Member

Will do. @MichalStrehovsky said there was a 6.0 issue for GS cookies somewhere, but I haven't been able to find it. Can anyone point me to it?

I meant that not respecting UnsafeValueType meets the 6.0 bar (it's security) and needs to be fixed independently of anything else. I'm not aware of an existing issue tracking this.

@jakobbotsch
Copy link
Member Author

Sample ARM64 diffs:

 ; ReadyToRun compilation
 ; optimized code
 ; fp based frame
-; partially interruptible
+; fully interruptible
 ; No PGO data
 ; 0 inlinees with PGO data; 2 single block inlinees; 0 inlinees without PGO data
 ; Final local variable assignments
@@ -6705,14 +6692,13 @@ G_M62437_IG05:
             adrp    x11, [HIGH RELOC #0xd1ffab1e]      // function address
             add     x11, x11, [LOW RELOC #0xd1ffab1e]
             ldr     x4, [x11]
-            blr     x4
-                                               ;; bbWeight=0.50 PerfScore 8.00
+                                               ;; bbWeight=0.50 PerfScore 7.50
 G_M62437_IG06:
             ldp     fp, lr, [sp],#16
-            ret     lr
+            br      x4
                                                ;; bbWeight=0.50 PerfScore 1.00

-; Total bytes of code 72, prolog size 8, PerfScore 19.95, instruction count 18, allocated bytes for code 72 (MethodHash=96c50c1a) for method OrdinalComparer:GetHashCode(System.String):int:this
+; Total bytes of code 68, prolog size 8, PerfScore 19.05, instruction count 17, allocated bytes for code 68 (MethodHash=96c50c1a) for method OrdinalComparer:GetHashCode(System.String):int:this
 ; Assembly listing for method System.Collections.Generic.List`1:TrimExcess():this
 ; Emitting BLENDED_CODE for generic ARM64 CPU - Unix
 ; ReadyToRun compilation
 ; optimized code
 ; fp based frame
-; partially interruptible
+; fully interruptible
 ; No PGO data
 ; Final local variable assignments
 ;
@@ -11353,38 +11341,44 @@ G_M54312_IG02:
             fcvtzs  w1, d16
             ldr     w11, [x0,#16]
             cmp     w11, w1
-            bge     G_M54312_IG04
+            bge     G_M54312_IG05
                                                ;; bbWeight=1    PerfScore 21.50
 G_M54312_IG03:
             mov     w1, w11
             adrp    x11, [HIGH RELOC #0xd1ffab1e]      // function address
             add     x11, x11, [LOW RELOC #0xd1ffab1e]
             ldr     x2, [x11]
-            blr     x2
-                                               ;; bbWeight=0.50 PerfScore 2.75
+                                               ;; bbWeight=0.50 PerfScore 2.25
 G_M54312_IG04:
+            ldp     fp, lr, [sp],#16
+            br      x2
+                                               ;; bbWeight=0.50 PerfScore 1.00
+G_M54312_IG05:
             ldp     fp, lr, [sp],#16
             ret     lr
-                                               ;; bbWeight=1    PerfScore 2.00
+                                               ;; bbWeight=0.50 PerfScore 1.00
 RWD00          dq      3FECCCCCCCCCCCCDh       ;          0.9


-; Total bytes of code 72, prolog size 8, PerfScore 34.95, instruction count 18, allocated bytes for code 72 (MethodHash=d6d32bd7) for method System.Collections.Generic.List`1:TrimExcess():this
+; Total bytes of code 76, prolog size 8, PerfScore 34.85, instruction count 19, allocated bytes for code 76 (MethodHash=d6d32bd7) for method System.Collections.Generic.List`1:TrimExcess():this

Summary (crossgen2 of frameworks + SPC):


Summary of Code Size diffs:
(Lower is better)

Total bytes of base: 52182848
Total bytes of diff: 51857084
Total bytes of delta: -325764 (-0.62% of base)
Total relative delta: NaN
    diff is an improvement.
    relative diff is a regression.
Detail diffs


Top file regressions (bytes):
         488 : System.Runtime.Numerics.dasm (0.51% of base)
          84 : System.Memory.dasm (0.10% of base)
          80 : System.Net.NameResolution.dasm (0.27% of base)
          28 : System.Net.WebProxy.dasm (0.49% of base)

Top file improvements (bytes):
      -39096 : Microsoft.Diagnostics.Tracing.TraceEvent.dasm (-0.80% of base)
      -37360 : Microsoft.CodeAnalysis.VisualBasic.dasm (-0.52% of base)
      -31816 : Microsoft.CodeAnalysis.CSharp.dasm (-0.55% of base)
      -29668 : System.Linq.Expressions.dasm (-0.97% of base)
      -22076 : System.Private.CoreLib.dasm (-0.47% of base)
      -16908 : System.Private.Xml.dasm (-0.37% of base)
      -13560 : Microsoft.CodeAnalysis.dasm (-0.71% of base)
       -8912 : System.Data.Common.dasm (-0.53% of base)
       -7580 : System.Private.DataContractSerialization.dasm (-0.70% of base)
       -5936 : System.Text.Json.dasm (-0.72% of base)
       -5236 : Newtonsoft.Json.dasm (-0.59% of base)
       -4484 : dotnet-Microsoft.XmlSerializer.Generator.dasm (-6.33% of base)
       -3416 : System.Net.Http.dasm (-0.43% of base)
       -3404 : System.Linq.dasm (-1.62% of base)
       -3108 : System.Configuration.ConfigurationManager.dasm (-0.66% of base)
       -3040 : System.Linq.Parallel.dasm (-0.64% of base)
       -2820 : System.Collections.Immutable.dasm (-1.05% of base)
       -2752 : System.ComponentModel.Composition.dasm (-0.81% of base)
       -2672 : System.Reflection.MetadataLoadContext.dasm (-0.97% of base)
       -2536 : System.Security.Cryptography.Algorithms.dasm (-0.62% of base)

193 total files with Code Size differences (189 improved, 4 regressed), 78 unchanged.

Top method regressions (bytes):
        2360 ( 1.12% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.CallInstruction:FastCreate(System.Reflection.MethodInfo,System.Reflection.ParameterInfo[]):System.Linq.Expressions.Interpreter.CallInstruction (183 methods)
        2016 (10.65% of base) : System.Private.CoreLib.dasm - System.ValueTuple`8:GetHashCodeCore(System.Collections.IEqualityComparer):int:this (14 methods)
         904 (19.50% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.CodeGen.ILBuilder:EmitNumericConversion(int,int,bool):this
         728 (16.05% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.JsonConverter`1:VerifyRead(ubyte,int,long,bool,byref):this (14 methods)
         552 (13.13% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.TypeUnification:CanUnifyHelper(Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithModifiers,Microsoft.CodeAnalysis.CSharp.Symbols.TypeWithModifiers,byref):bool
         500 (25.56% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.CodeGen.CodeGenerator:EmitExpressionCore(Microsoft.CodeAnalysis.VisualBasic.BoundExpression,bool):this
         472 (18.02% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.CodeGen.CodeGenerator:EmitExpressionCore(Microsoft.CodeAnalysis.CSharp.BoundExpression,bool):this
         464 (103.57% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.Diagnostics.SuppressMessageAttributeState:IsDiagnosticSuppressed(System.String,Microsoft.CodeAnalysis.ISymbol,byref):bool:this
         456 (14.75% of base) : System.Private.CoreLib.dasm - System.Reflection.Emit.CustomAttributeBuilder:EmitValue(System.IO.BinaryWriter,System.Type,System.Object)
         424 (26.57% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.LightCompiler:CompileNoLabelPush(System.Linq.Expressions.Expression):this
         400 (18.73% of base) : System.Private.Xml.dasm - System.Xml.Schema.XmlListConverter:ChangeListType(System.Object,System.Type,System.Xml.IXmlNamespaceResolver):System.Object:this
         340 (24.78% of base) : System.Reflection.Metadata.dasm - System.Reflection.Metadata.Ecma335.MetadataBuilder:SetCapacity(ubyte,int):this
         320 (33.90% of base) : System.Private.CoreLib.dasm - System.Reflection.Emit.ModuleBuilder:GetMemberRefSignature(System.Reflection.MethodBase,int):System.Reflection.Emit.SignatureHelper:this
         312 ( 2.95% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.ArrayBuilder`1:RemoveDuplicates():this (24 methods)
         292 (20.92% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.ExpressionLambdaRewriter:VisitExpressionWithoutStackGuard(Microsoft.CodeAnalysis.CSharp.BoundExpression):Microsoft.CodeAnalysis.CSharp.BoundExpression:this
         288 (24.74% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.LanguageParser:ParseStatementNoDeclaration(bool):Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.StatementSyntax:this
         284 (31.00% of base) : System.Reflection.MetadataLoadContext.dasm - System.Reflection.SignatureTypeExtensions:TryResolve(System.Type,System.Type[]):System.Type
         272 (30.09% of base) : System.Private.CoreLib.dasm - System.Reflection.SignatureTypeExtensions:TryResolve(System.Reflection.SignatureType,System.Type[]):System.Type
         260 ( 4.85% of base) : System.Private.DataContractSerialization.dasm - System.Runtime.Serialization.DataNode`1:AddQualifiedNameAttribute(System.Runtime.Serialization.ElementData,System.String,System.String,System.String,System.String,System.String):this (13 methods)
         256 (26.12% of base) : Microsoft.CSharp.dasm - Microsoft.CSharp.RuntimeBinder.ExpressionTreeCallRewriter:GenerateBinaryOperator(Microsoft.CSharp.RuntimeBinder.Semantics.ExprCall):System.Linq.Expressions.Expression:this

Top method improvements (bytes):
      -14984 (-1.49% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.FuncCallInstruction`3:Run(System.Linq.Expressions.Interpreter.InterpretedFrame):int:this (1873 methods)
       -7492 (-3.03% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.FuncCallInstruction`3:ToString():System.String:this (1873 methods)
       -1160 (-1.69% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.ActionCallInstruction`2:Run(System.Linq.Expressions.Interpreter.InterpretedFrame):int:this (145 methods)
       -1160 (-2.13% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.FuncCallInstruction`2:Run(System.Linq.Expressions.Interpreter.InterpretedFrame):int:this (145 methods)
        -580 (-3.03% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.ActionCallInstruction`2:ToString():System.String:this (145 methods)
        -580 (-3.03% of base) : System.Linq.Expressions.dasm - System.Linq.Expressions.Interpreter.FuncCallInstruction`2:ToString():System.String:this (145 methods)
        -312 (-4.03% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1:ReadJsonAndSetMember(System.Object,byref,byref):bool:this (13 methods)
        -224 (-7.25% of base) : System.Text.Json.dasm - System.Text.Json.JsonSerializer:WriteUsingGeneratedSerializer(System.Text.Json.Utf8JsonWriter,byref,System.Text.Json.Serialization.Metadata.JsonTypeInfo) (14 methods)
        -224 (-14.29% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1:get_ConstructorIsParameterized():bool:this (14 methods)
        -224 (-5.80% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1:OnTryRead(byref,System.Type,System.Text.Json.JsonSerializerOptions,byref,byref):bool:this (14 methods)
        -168 (-3.97% of base) : System.Text.Json.dasm - System.Text.Json.Nodes.JsonValueTrimmable`1:WriteTo(System.Text.Json.Utf8JsonWriter,System.Text.Json.JsonSerializerOptions):this (14 methods)
        -168 (-11.11% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1:get_ElementType():System.Type:this (14 methods)
        -168 (-11.11% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Converters.JsonMetadataServicesConverter`1:get_KeyType():System.Type:this (14 methods)
        -168 (-9.61% of base) : System.Text.Json.dasm - System.Text.Json.Serialization.Metadata.JsonPropertyInfo`1:SetExtensionDictionaryAsObject(System.Object,System.Object):this (14 methods)
        -152 (-2.56% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.ArrayBuilder`1:Free():this (38 methods)
        -152 (-2.67% of base) : System.Private.CoreLib.dasm - System.Collections.Generic.EqualityComparer`1:System.Collections.IEqualityComparer.Equals(System.Object,System.Object):bool:this (19 methods)
        -144 (-1.30% of base) : System.Data.Common.dasm - System.Data.RBTree`1:RBDeleteX(int,int,int):int:this (2 methods)
        -128 (-30.77% of base) : System.Collections.Immutable.dasm - Node:get_Item(int):System.__Canon:this (2 methods)
        -128 (-48.48% of base) : System.Collections.Immutable.dasm - Node:ItemRefUnchecked(int):byref:this (2 methods)
        -120 (-11.49% of base) : System.Private.CoreLib.dasm - System.Threading.Tasks.ContinuationTaskFromResultTask`1:InnerInvoke():this (5 methods)

Top method regressions (percentages):
         464 (103.57% of base) : Microsoft.CodeAnalysis.dasm - Microsoft.CodeAnalysis.Diagnostics.SuppressMessageAttributeState:IsDiagnosticSuppressed(System.String,Microsoft.CodeAnalysis.ISymbol,byref):bool:this
          20 (62.50% of base) : System.Private.CoreLib.dasm - System.IO.Path:TrimEndingDirectorySeparator(System.ReadOnlySpan`1[System.Char]):System.ReadOnlySpan`1[System.Char]
          20 (62.50% of base) : System.Runtime.Numerics.dasm - System.Numerics.BigInteger:Divide(System.Numerics.BigInteger,System.Numerics.BigInteger):System.Numerics.BigInteger
          20 (62.50% of base) : System.Runtime.Numerics.dasm - System.Numerics.BigInteger:Multiply(System.Numerics.BigInteger,System.Numerics.BigInteger):System.Numerics.BigInteger
          20 (62.50% of base) : System.Runtime.Numerics.dasm - System.Numerics.BigInteger:Remainder(System.Numerics.BigInteger,System.Numerics.BigInteger):System.Numerics.BigInteger
         152 (52.78% of base) : System.Data.Common.dasm - System.Data.XSDSchema:ParseDataType(System.String):System.Type:this
          24 (50.00% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.Symbols.MethodSignatureComparer:SubstituteType(Microsoft.CodeAnalysis.VisualBasic.Symbols.TypeSubstitution,Microsoft.CodeAnalysis.VisualBasic.Symbols.TypeWithModifiers):Microsoft.CodeAnalysis.VisualBasic.Symbols.TypeWithModifiers
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Add(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:BitwiseAnd(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:BitwiseOr(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Divide(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Mod(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Modulus(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Multiply(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:OnesComplement(System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Subtract(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlInt64:Xor(System.Data.SqlTypes.SqlInt64,System.Data.SqlTypes.SqlInt64):System.Data.SqlTypes.SqlInt64
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlMoney:Add(System.Data.SqlTypes.SqlMoney,System.Data.SqlTypes.SqlMoney):System.Data.SqlTypes.SqlMoney
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlMoney:Divide(System.Data.SqlTypes.SqlMoney,System.Data.SqlTypes.SqlMoney):System.Data.SqlTypes.SqlMoney
          16 (50.00% of base) : System.Data.Common.dasm - System.Data.SqlTypes.SqlMoney:Multiply(System.Data.SqlTypes.SqlMoney,System.Data.SqlTypes.SqlMoney):System.Data.SqlTypes.SqlMoney

Top method improvements (percentages):
         -24 (-66.67% of base) : System.Private.Xml.dasm - System.Xml.Xsl.Runtime.XmlAttributeCache:WriteValue(System.String):this
         -52 (-59.09% of base) : System.Private.CoreLib.dasm - System.IO.Strategies.DerivedFileStreamStrategy:DisposeAsync():System.Threading.Tasks.ValueTask:this
         -36 (-52.94% of base) : System.Drawing.Common.dasm - System.Drawing.Drawing2D.GraphicsPath:GetBounds(System.Drawing.Drawing2D.Matrix):System.Drawing.RectangleF:this
         -52 (-52.00% of base) : Microsoft.CodeAnalysis.dasm - Enumerator:get_Current():Microsoft.CodeAnalysis.CodeGen.SwitchIntegralJumpTableEmitter+SwitchBucket:this
         -36 (-50.00% of base) : System.Drawing.Common.dasm - System.Drawing.Drawing2D.GraphicsPath:GetBounds():System.Drawing.RectangleF:this
        -128 (-48.48% of base) : System.Collections.Immutable.dasm - Node:ItemRefUnchecked(int):byref:this (2 methods)
         -28 (-46.67% of base) : Microsoft.CodeAnalysis.dasm - <>c__DisplayClass5_0:<.ctor>b__0(System.String):System.Collections.Generic.KeyValuePair`2[System.String, System.Xml.Linq.XDocument]:this
         -28 (-46.67% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.Symbols.SourceMethodSymbol:GetReturnTypeAttributeDeclarations():Roslyn.Utilities.OneOrMany`1[Microsoft.CodeAnalysis.SyntaxList`1[Microsoft.CodeAnalysis.CSharp.Syntax.AttributeListSyntax]]:this
         -24 (-46.15% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Candidate:get_FixedTypeParameters():Microsoft.CodeAnalysis.BitVector:this
         -24 (-46.15% of base) : System.Net.Http.dasm - Http3ReadStream:<>n__0():System.Threading.Tasks.ValueTask:this
         -24 (-46.15% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.SyntaxFactory:NodeOrTokenList(Microsoft.CodeAnalysis.SyntaxNodeOrToken[]):Microsoft.CodeAnalysis.SyntaxNodeOrTokenList
         -24 (-46.15% of base) : Microsoft.CodeAnalysis.VisualBasic.dasm - Microsoft.CodeAnalysis.VisualBasic.SyntaxFactory:NodeOrTokenList(Microsoft.CodeAnalysis.SyntaxNodeOrToken[]):Microsoft.CodeAnalysis.SyntaxNodeOrTokenList
         -24 (-46.15% of base) : System.Private.CoreLib.dasm - System.IO.FileStream:BaseDisposeAsync():System.Threading.Tasks.ValueTask:this
         -24 (-46.15% of base) : System.Net.Security.dasm - System.Net.Security.NegotiateStream:<>n__0():System.Threading.Tasks.ValueTask:this
         -24 (-46.15% of base) : System.Net.Security.dasm - System.Net.Security.SslStream:<>n__0():System.Threading.Tasks.ValueTask:this
         -28 (-43.75% of base) : Microsoft.CodeAnalysis.CSharp.dasm - Microsoft.CodeAnalysis.CSharp.CSharpSemanticModel:GetTypeInfoCore(Microsoft.CodeAnalysis.SyntaxNode,System.Threading.CancellationToken):Microsoft.CodeAnalysis.TypeInfo:this
         -28 (-43.75% of base) : System.Net.HttpListener.dasm - System.Net.ListenerAsyncResult:get_CompletedSynchronously():bool:this
         -36 (-42.86% of base) : Microsoft.CodeAnalysis.dasm - Enumerator:get_Current():Microsoft.CodeAnalysis.CodeGen.ClosureDebugInfo:this
         -36 (-42.86% of base) : Microsoft.CodeAnalysis.dasm - Enumerator:get_Current():Microsoft.CodeAnalysis.CodeGen.LocalSlotDebugInfo:this
         -36 (-42.86% of base) : Microsoft.CodeAnalysis.dasm - Enumerator:get_Current():Microsoft.CodeAnalysis.Text.TextChangeRange:this

76051 total methods with Code Size differences (72199 improved, 3852 regressed), 154874 unchanged.


@jakobbotsch
Copy link
Member Author

FWIW, the FSharp.Core.dll diffs look like the following. It indicates that ~1100 more functions were crossgenned.

Summary of Code Size diffs:
(Lower is better)

Total bytes of base: 794036
Total bytes of diff: 977634
Total bytes of delta: 183598 (23.12% of base)
Total relative delta: -44.35
    diff is a regression.
    relative diff is an improvement.


Total byte diff includes 181609 bytes from reconciling methods
        Base had    0 unique methods,        0 unique bytes
        Diff had 1088 unique methods,   181609 unique bytes

Top file regressions (bytes):
      183598 : FSharp.Core.dasm (23.12% of base)

1 total files with Code Size differences (0 improved, 1 regressed), 0 unchanged.

Top method regressions (bytes):
       11879 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Quotations.FSharpExpr:GetLayout(bool):Microsoft.FSharp.Text.StructuredPrintfImpl.Layout:this (0 base, 1 diff methods)
        9060 (      of base) : FSharp.Core.dasm - HashCompare:GenericEqualityObj$cont@1336(bool,System.Collections.IEqualityComparer,System.Object,System.Object,System.Array,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
        6959 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.QueryModule:EvalNonNestedOuter(int,Microsoft.FSharp.Quotations.FSharpExpr):System.Object (0 base, 1 diff methods)
        5828 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.QueryModule:TransNestedOuter(int,Microsoft.FSharp.Quotations.FSharpExpr):Microsoft.FSharp.Quotations.FSharpExpr (0 base, 1 diff methods)
        4026 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:ToString():System.String:this (0 base, 3 diff methods)
        2353 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:eq@197(Microsoft.FSharp.Quotations.Tree,Microsoft.FSharp.Quotations.Tree):bool (0 base, 1 diff methods)
        2047 (      of base) : FSharp.Core.dasm - MakeGroupJoin@955:Invoke(System.Tuple`8[System.Boolean, System.Type, System.Type, System.Type, System.Type, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpExpr, System.Tuple`7[Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr]]):Microsoft.FSharp.Quotations.FSharpExpr:this (0 base, 1 diff methods)
        1961 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpList`1:ToString():System.String:this (0 base, 2 diff methods)
        1960 (      of base) : FSharp.Core.dasm - MakeJoin@939:Invoke(System.Tuple`8[System.Boolean, System.Type, System.Type, System.Type, System.Type, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpExpr, System.Tuple`7[Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr]]):Microsoft.FSharp.Quotations.FSharpExpr:this (0 base, 1 diff methods)
        1882 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Core.FSharpOption`1:Equals(System.Object,System.Collections.IEqualityComparer):bool:this (0 base, 14 diff methods)
        1862 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Core.FSharpOption`1:CompareTo(System.Object,System.Collections.IComparer):int:this (0 base, 14 diff methods)
        1779 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@145-6(Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Quotations.ExprConstInfo,System.Collections.IEqualityComparer,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
        1659 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Quotations.PatternsModule:typeOf(System.__Canon):System.Type (0 base, 1 diff methods)
        1656 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@145-8(Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
        1655 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.RuntimeHelpers.Adapters:ConvImmutableTypeToMutableType(Microsoft.FSharp.Linq.RuntimeHelpers.Adapters+ConversionDescription,System.Type):System.Type (0 base, 1 diff methods)
        1461 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.QueryModule:ConvMutableToImmutable(Microsoft.FSharp.Linq.RuntimeHelpers.Adapters+ConversionDescription,Microsoft.FSharp.Quotations.FSharpExpr):Microsoft.FSharp.Quotations.FSharpExpr (0 base, 1 diff methods)
        1435 (      of base) : FSharp.Core.dasm - Microsoft.FSharp.Reflection.Impl:mkTupleType(bool,System.Reflection.Assembly,System.Type[]):System.Type (0 base, 1 diff methods)
        1362 (     ∞ of base) : FSharp.Core.dasm - Microsoft.FSharp.Linq.QueryModule:Make@575-3(bool,Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`2[Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Core.FSharpFunc`2[System.Tuple`3[Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Collections.FSharpList`1[System.Type], Microsoft.FSharp.Collections.FSharpList`1[Microsoft.FSharp.Quotations.FSharpExpr]], Microsoft.FSharp.Quotations.FSharpExpr],Microsoft.FSharp.Quotations.FSharpExpr,bool,Microsoft.FSharp.Quotations.FSharpExpr,Microsoft.FSharp.Quotations.FSharpVar,Microsoft.FSharp.Quotations.FSharpExpr):Microsoft.FSharp.Quotations.FSharpExpr (0 base, 1 diff methods)
        1312 (      of base) : FSharp.Core.dasm - MakeSelectMany@793:Invoke(System.Tuple`7[System.Boolean, System.Type, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr, Microsoft.FSharp.Quotations.FSharpVar, Microsoft.FSharp.Quotations.FSharpExpr]):Microsoft.FSharp.Quotations.FSharpExpr:this (0 base, 1 diff methods)
        1240 (      of base) : FSharp.Core.dasm - PrintfEnv`3:RunSteps(System.Object[],System.Type[],Microsoft.FSharp.Core.PrintfImpl+Step[]):System.__Canon:this (0 base, 1 diff methods)

Top method improvements (bytes):
         -24 (-23.53% of base) : FSharp.Core.dasm - Microsoft.FSharp.Control.AsyncActivation`1:get_IsCancellationRequested():bool:this (3 methods)
         -20 (-32.26% of base) : FSharp.Core.dasm - mkSeq@132:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this (2 methods)
         -18 (-19.78% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:ContainsKey(int):bool:this (2 methods)
         -18 (-33.33% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:GetHashCode():int:this (3 methods)
         -18 (-19.78% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IDictionary<'Key, 'Value>.ContainsKey(int):bool:this (2 methods)
         -18 (-17.31% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IDictionary<'Key, 'Value>.TryGetValue(int,byref):bool:this (2 methods)
         -18 (-19.78% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IReadOnlyDictionary<'Key, 'Value>.ContainsKey(int):bool:this (2 methods)
         -18 (-17.31% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IReadOnlyDictionary<'Key, 'Value>.TryGetValue(int,byref):bool:this (2 methods)
         -18 (-17.31% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:TryGetValue(int,byref):bool:this (2 methods)
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:get_Item(int):int:this
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IDictionary<'Key, 'Value>.get_Item(int):int:this
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IReadOnlyDictionary<'Key, 'Value>.get_Item(int):int:this
         -16 (-41.03% of base) : FSharp.Core.dasm - Microsoft.FSharp.Reflection.UnionCaseInfo:GetFields():System.Reflection.PropertyInfo[]:this
         -16 (-41.03% of base) : FSharp.Core.dasm - Microsoft.FSharp.Reflection.UnionCaseInfo:getMethInfo():System.Reflection.MethodInfo:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeByte@5429-1:System.Collections.Generic.IEnumerable<System.Byte>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Byte]:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeByte@5429-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-41.03% of base) : FSharp.Core.dasm - RangeInt16@5426-1:System.Collections.Generic.IEnumerable<System.Int16>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Int16]:this
         -16 (-41.03% of base) : FSharp.Core.dasm - RangeInt16@5426-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeInt32@5420-1:System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Int32]:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeInt32@5420-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this

Top method regressions (percentages):
          21 (      of base) : FSharp.Core.dasm - |RecordFieldGetSimplification|_|@170:Invoke(System.Reflection.PropertyInfo):bool:this (0 base, 1 diff methods)
        2353 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:eq@197(Microsoft.FSharp.Quotations.Tree,Microsoft.FSharp.Quotations.Tree):bool (0 base, 1 diff methods)
         360 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@137-5(Microsoft.FSharp.Quotations.Tree,Microsoft.FSharp.Quotations.Tree,System.Collections.IEqualityComparer,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
         366 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@137-7(Microsoft.FSharp.Quotations.Tree,Microsoft.FSharp.Quotations.Tree,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
        1779 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@145-6(Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Quotations.ExprConstInfo,System.Collections.IEqualityComparer,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
        1656 (      of base) : FSharp.Core.dasm - <StartupCode$FSharp-Core>.$Quotations:Equals$cont@145-8(Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Quotations.ExprConstInfo,Microsoft.FSharp.Core.Unit):bool (0 base, 1 diff methods)
          17 (      of base) : FSharp.Core.dasm - a@1498:Invoke(Microsoft.FSharp.Quotations.FSharpExpr):System.Type:this (0 base, 1 diff methods)
          17 (      of base) : FSharp.Core.dasm - a@1498-1:Invoke(Microsoft.FSharp.Quotations.FSharpExpr):System.Type:this (0 base, 1 diff methods)
          16 (      of base) : FSharp.Core.dasm - aboveListL@284:Invoke(Microsoft.FSharp.Text.StructuredPrintfImpl.Layout,Microsoft.FSharp.Text.StructuredPrintfImpl.Layout):Microsoft.FSharp.Text.StructuredPrintfImpl.Layout:this (0 base, 1 diff methods)
          44 (      of base) : FSharp.Core.dasm - action@647-12:Invoke(Microsoft.FSharp.Core.Unit):Microsoft.FSharp.Control.AsyncReturn:this (0 base, 1 diff methods)
          52 (      of base) : FSharp.Core.dasm - Adapt@3242:Invoke(int,int):bool:this (0 base, 1 diff methods)
          53 (      of base) : FSharp.Core.dasm - Adapt@3242:Invoke(int,ushort):ushort:this (0 base, 1 diff methods)
          53 (      of base) : FSharp.Core.dasm - Adapt@3242:Invoke(System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
          53 (      of base) : FSharp.Core.dasm - Adapt@3257-1:Invoke(System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
          93 (      of base) : FSharp.Core.dasm - Adapt@3260-2:Invoke(System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
          50 (      of base) : FSharp.Core.dasm - Adapt@3274-3:Invoke(System.__Canon,System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
         101 (      of base) : FSharp.Core.dasm - Adapt@3279-4:Invoke(System.__Canon,System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
         109 (      of base) : FSharp.Core.dasm - Adapt@3282-5:Invoke(System.__Canon,System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
          60 (      of base) : FSharp.Core.dasm - Adapt@3299-6:Invoke(System.__Canon,System.__Canon,System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)
         109 (      of base) : FSharp.Core.dasm - Adapt@3304-7:Invoke(System.__Canon,System.__Canon,System.__Canon,System.__Canon,System.__Canon):System.__Canon:this (0 base, 1 diff methods)

Top method improvements (percentages):
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:get_Item(int):int:this
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IDictionary<'Key, 'Value>.get_Item(int):int:this
         -16 (-47.06% of base) : FSharp.Core.dasm - Microsoft.FSharp.Collections.FSharpMap`2:System.Collections.Generic.IReadOnlyDictionary<'Key, 'Value>.get_Item(int):int:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeInt32@5420-1:System.Collections.Generic.IEnumerable<System.Int32>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Int32]:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeInt32@5420-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeUInt32@5423-1:System.Collections.Generic.IEnumerable<System.UInt32>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.UInt32]:this
         -16 (-45.71% of base) : FSharp.Core.dasm - RangeUInt32@5423-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -13 (-44.83% of base) : FSharp.Core.dasm - -cctor@6137-17:Invoke(System.Decimal):System.Decimal:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeByte@5429-1:System.Collections.Generic.IEnumerable<System.Byte>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Byte]:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeByte@5429-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeInt64@5421-1:System.Collections.Generic.IEnumerable<System.Int64>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Int64]:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeInt64@5421-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeUInt16@5427-1:System.Collections.Generic.IEnumerable<System.UInt16>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.UInt16]:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeUInt16@5427-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeUInt64@5422-1:System.Collections.Generic.IEnumerable<System.UInt64>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.UInt64]:this
         -16 (-43.24% of base) : FSharp.Core.dasm - RangeUInt64@5422-1:System.Collections.IEnumerable.GetEnumerator():System.Collections.IEnumerator:this
         -16 (-43.24% of base) : FSharp.Core.dasm - substargs@1760:Invoke(Microsoft.FSharp.Quotations.FSharpExpr):Microsoft.FSharp.Quotations.FSharpExpr:this
         -16 (-41.03% of base) : FSharp.Core.dasm - Microsoft.FSharp.Reflection.UnionCaseInfo:GetFields():System.Reflection.PropertyInfo[]:this
         -16 (-41.03% of base) : FSharp.Core.dasm - Microsoft.FSharp.Reflection.UnionCaseInfo:getMethInfo():System.Reflection.MethodInfo:this
         -16 (-41.03% of base) : FSharp.Core.dasm - RangeInt16@5426-1:System.Collections.Generic.IEnumerable<System.Int16>.GetEnumerator():System.Collections.Generic.IEnumerator`1[System.Int16]:this

2309 total methods with Code Size differences (288 improved, 2021 regressed), 5307 unchanged.

@dsyme
Copy link

dsyme commented Sep 27, 2021

FWIW, the FSharp.Core.dll diffs look like the following. It indicates that ~1100 more functions were crossgenned.

That's great! Any idea what proportion remain non-cross-gen'd? And what's a typical proportion in other DLLs?

@jakobbotsch
Copy link
Member Author

jakobbotsch commented Sep 27, 2021

That's great! Any idea what proportion remain non-cross-gen'd? And what's a typical proportion in other DLLs?

For Windows x64 the data looks as follows. These results will be different for ARM64 or Linux x64.

FSharp.Core.dll before this change:

Reason Number of functions Pct
None 7941 85.5%
fIsTailPrefix requires runtime JIT 1177 12.7%
it always throws an exception 162 1.7%
CORINFO_HELP_INITINSTCLASS requires runtime JIT 13 0.1%

FSharp.Core.dll after this change:

Reason Number of functions Pct
None 9157 97.6%
it always throws an exception 162 1.7%
getTailCallHelpers requires runtime JIT 38 0.4%
CORINFO_HELP_INITINSTCLASS requires runtime JIT 26 0.3%

Hopefully these results can be approximately extrapolated to the full F# compiler stack.

For reference here is System.Private.CoreLib.dll:

Reason Number of functions Pct
None 28129 89.5%
it always throws an exception 3197 10.2%
CORINFO_BOX_THIS requires runtime JIT 66 0.2%
[S.P.CoreLib]System.Numerics.Vector1` requires runtime JIT 19 0.1%
[S.P.CoreLib]System.Numerics.Vector1` requires runtime JIT 6 0.0%
This function is using SIMD intrinsics, their size is machine specific requires runtime JIT 6 0.0%
CORINFO_HELP_THROW_ARGUMENTEXCEPTION requires runtime JIT 3 0.0%
SVM requires runtime JIT 3 0.0%
CORINFO_HELP_TYPEHANDLE_TO_RUNTIMETYPE_MAYBENULL requires runtime JIT 3 0.0%

@trylek
Copy link
Member

trylek commented Sep 27, 2021

Thanks Jakob for making these improvements and for sharing the data, that indeed looks promising! For the SPC breakdown, by always throws an exception you mean that the compilation throws some other error bucket than those summarized below or that the original MSIL function contains just a single throw statement?

@jakobbotsch
Copy link
Member Author

For the SPC breakdown, by always throws an exception you mean that the compilation throws some other error bucket than those summarized below or that the original MSIL function contains just a single throw statement?

The latter (or rather, the check used is FunctionJustThrows which is a bit more complex, but same idea). That reason is coming from here:

if (!FunctionJustThrows(methodIL))
{
if (MethodBeingCompiled.GetTypicalMethodDefinition() is EcmaMethod ecmaMethod)
{
// Harvest the method being compiled for the purpose of populating the type resolver
var resolver = _compilation.NodeFactory.Resolver;
resolver.AddModuleTokenForMethod(MethodBeingCompiled, new ModuleToken(ecmaMethod.Module, ecmaMethod.Handle));
}
CompileMethodInternal(methodCodeNodeNeedingCode, methodIL);
codeGotPublished = true;
}
else
{
if (logger.IsVerbose)
logger.Writer.WriteLine($"Warning: Method `{MethodBeingCompiled}` was not compiled because it always throws an exception");
}

@trylek
Copy link
Member

trylek commented Sep 27, 2021

I see, thanks for the detailed explanation. I'm wondering whether that's what we want to keep long-term i.o.w. whether we have any metrics to assess to what extent the executable size savings compensate for the huge code graph and energy consumption incurred by spinning up JIT to code up the couple of dozens of assembly bytes.

@jkotas
Copy link
Member

jkotas commented Sep 27, 2021

I see, thanks for the detailed explanation. I'm wondering whether that's what we want to keep long-term i.o.w. whether we have any metrics to assess to what extent the executable size savings compensate for the huge code graph and energy consumption incurred by spinning up JIT to code up the couple of dozens of assembly bytes.

I think we are doing the right trade-off:

  • Every .NET Core app loads the JIT these days, so the fixed cost of warming up the JIT is paid for.
  • These throw-only methods are going to be only JITed in rare cases where an exception is thrown.

@NinoFloris
Copy link
Contributor

@jakobbotsch I see there are some CORINFO_HELP_INITINSTCLASS cases in the FSharp.Core diff, and none in the SPC breakdown. I couldn't find much more on it than was covered in #6902 but it looks like methods responsible for these cases would be referencing generic classes that have static constructors? Would it be possible for you to extract the methods responsible from the results?

@jakobbotsch
Copy link
Member Author

@NinoFloris They are:

Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.onCancel@1603-2<__Canon,__Canon>(IEvent`2<__Canon,__Canon>,FSharpOption`1<FSharpFunc`2<Unit,Unit>>,CancellationToken,ResultCell`1<AsyncResult`1<__Canon>>,Once,Lazy`1<__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.beginAction@1594<__Canon,__Canon,__Canon>(FSharpFunc`2<__Canon,FSharpAsync`1<__Canon>>)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.onCancel@1528<__Canon>(FSharpOption`1<FSharpFunc`2<Unit,Unit>>,CancellationToken,ResultCell`1<AsyncResult`1<__Canon>>,Once,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.finishTask@1186<__Canon>(AsyncActivation`1<__Canon[]>,__Canon[],LinkedSubSource,FSharpRef`1<FSharpOption`1<FSharpChoice`2<ExceptionDispatchInfo,OperationCanceledException>>>,int32)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.recordFailure@1203<__Canon>(AsyncActivation`1<__Canon[]>,__Canon[],LinkedSubSource,FSharpRef`1<int32>,FSharpRef`1<FSharpOption`1<FSharpChoice`2<ExceptionDispatchInfo,OperationCanceledException>>>,FSharpChoice`2<ExceptionDispatchInfo,OperationCanceledException>)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.worker@1242<__Canon>(FSharpAsync`1<__Canon>[],AsyncActivation`1<__Canon[]>,__Canon[],LinkedSubSource,FSharpRef`1<int32>,FSharpRef`1<FSharpOption`1<FSharpChoice`2<ExceptionDispatchInfo,OperationCanceledException>>>,FSharpRef`1<int32>,TrampolineHolder)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Async.once@1094<__Canon,__Canon>(AsyncActivation`1<__Canon>,Thread,Latch,FSharpRef`1<bool>,FSharpRef`1<FSharpOption`1<FSharpFunc`2<Unit,AsyncReturn>>>,FSharpFunc`2<__Canon,AsyncReturn>,__Canon)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]Microsoft.FSharp.Core.PrintfImpl.convFunc@1149<__Canon>(FormatSpecifier)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]Microsoft.FSharp.Core.PrintfImpl.buildCaptureFunc$cont@1088<__Canon,__Canon,__Canon,__Canon>(Type,Type[],__Canon,Type,FSharpOption`1<object>,bool,Type[],object,int32,int32,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]Microsoft.FSharp.Core.PrintfImpl.TextWriterPrintfEnv<__Canon>(FSharpFunc`2<Unit,__Canon>,TextWriter)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]Microsoft.FSharp.Core.PrintfImpl.StringBuilderPrintfEnv<__Canon>(FSharpFunc`2<Unit,__Canon>,StringBuilder)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]Microsoft.FSharp.Core.PrintfImpl.revToArray<__Canon>(int32,FSharpList`1<__Canon>)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3203-4<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.copy@3563<__Canon>(int32,__Canon[],FSharpList`1<__Canon>,int32)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.Equals$cont@3193-2<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.Equals$cont@3203-4<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.Equals$cont@3193-1<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,IEqualityComparer,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.GetHashCode$cont@3193<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(IEqualityComparer,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.Equals$cont@3203-3<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,IEqualityComparer,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3193-3<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(IComparer,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.GetHashCode$cont@3203-1<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(IEqualityComparer,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3193-2<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`6<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3203-5<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>(IComparer,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`7<__Canon,__Canon,__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.Equals$cont@3184<__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`5<__Canon,__Canon,__Canon,__Canon,__Canon>,object,IEqualityComparer,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3184-1<__Canon,__Canon,__Canon,__Canon,__Canon>(IComparer,FSharpChoice`5<__Canon,__Canon,__Canon,__Canon,__Canon>,object,FSharpChoice`5<__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[FSharp.Core]<StartupCode$FSharp-Core>.$Prim-types.CompareTo$cont@3184<__Canon,__Canon,__Canon,__Canon,__Canon>(FSharpChoice`5<__Canon,__Canon,__Canon,__Canon,__Canon>,FSharpChoice`5<__Canon,__Canon,__Canon,__Canon,__Canon>,Unit)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT

I also tried Microsoft.CodeAnalysis.CSharp.dll and it has a couple too, so it's not totally unique to F#:

Info: Method `[Microsoft.CodeAnalysis.CSharp]Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxToken.WithValue<__Canon>(SyntaxKind,CSharpSyntaxNode,string,__Canon,CSharpSyntaxNode)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
Info: Method `[Microsoft.CodeAnalysis.CSharp]Microsoft.CodeAnalysis.CSharp.Syntax.InternalSyntax.SyntaxToken.WithValue<__Canon>(SyntaxKind,string,__Canon)` was not compiled because `CORINFO_HELP_INITINSTCLASS` requires runtime JIT
`` 

@davidwrighton
Copy link
Member

@jakobbotsch This needs to bump the R2R minor version number. The number is duplicated in both src/coreclr/tools/Common/Internal/Runtime/ModuleHeaders.cs and src/coreclr/inc/readytorun.h

@jkotas
Copy link
Member

jkotas commented Oct 1, 2021

bump the R2R minor version number

I do not think it is required. This change does not add anything new to the format. Everything that it needed is supported by the runtime already - there are no runtime changes.

Copy link
Member

@AndyAyersMS AndyAyersMS left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

JIT changes LGTM.

Just one small question.

else
{
// Register where we save call address in should not be overridden by epilog.
assert((tmpReg & (RBM_INT_CALLEE_TRASH & ~RBM_LR)) == tmpReg);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm confused about the role of tmpReg in the fast tail call case. How does it end up having the right contents?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It happens in genCall here: https://github.com/jakobbotsch/runtime/blob/9f70cc42d73467c15a458ee9774589271d721536/src/coreclr/jit/codegenarmarch.cpp#L2340-L2375

For normal calls we call genCall which then calls genCallInstruction that takes care to generate the code to load the call target and do the call.
For tailcalls we instead generate the code to load the call target in genCall, but this is the last thing that happens when we see the GenTreeCall node. The remaining work happens during epilog generation which also calls genCallInstruction.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So you could pass REG_NA for the tail call case?

I guess it's GetSingleTempReg that is confusing me. It seems odd to "allocate" a temp reg without altering state.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It seems odd to "allocate" a temp reg without altering state.

Not sure I understand. The temp reg is allocated during RA for this specific optimization we do on ARM/ARM64, where we have no target node and need an extra register to store the call target loaded from the indirection cell. We still need it for the tail call case.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Right, not that it's not ultimately needed, but that the value of tmpReg passed here to GenCall is not used, instead we go call GetSingleTempReg again.

It's not that important, I just found it confusing to follow how the value gets from one place to another.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This code here in genCallInstruction is called last. genCall also calls GetSingleTempReg, but it adds the register back to gtRsvdRegs so that this call will succeed:
https://github.com/jakobbotsch/runtime/blob/9f70cc42d73467c15a458ee9774589271d721536/src/coreclr/jit/codegenarmarch.cpp#L2369-L2370

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, makes more sense now.

}

return false;
return true;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This cannot be just true. It must respect the same set of rules that are implemented in canTailCall in jitinterface.cpp. Notably if there is no tail prefix the following situations are forbidden from tail call optimization

  • If the Caller method is NoInline
  • If the Caller method is the entrypoint to the application
  • If the Callee method has the RequireSecObject bit set on the MethodDef

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Addressed this, PTAL.

Copy link
Member

@davidwrighton davidwrighton left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🕐

Do not do implicit tailcalls when
* The caller is the entry point
* The caller is marked NoInline
* The callee requires security object
@jakobbotsch jakobbotsch merged commit 367b006 into dotnet:main Oct 7, 2021
@jakobbotsch jakobbotsch deleted the cg2-fast-tailcalls branch October 7, 2021 08:16
@forki
Copy link

forki commented Oct 8, 2021

will this be in .NET 6?

@jakobbotsch jakobbotsch linked an issue Oct 8, 2021 that may be closed by this pull request
@jakobbotsch
Copy link
Member Author

will this be in .NET 6?

No, we currently do not plan to backport this work to .NET 6.

// However, for tail calls, the call target is always computed in RBM_FASTTAILCALL_TARGET
// and so do not optimize virtual stub calls for such cases.
shouldOptimizeVirtualStubCall = !call->IsTailCall();
shouldOptimizeVirtualStubCall = true;
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@EgorBo this is the change that fixes #60025, along with fixing the JIT to load the call target for tailcalls while processing the GenTreeCall node instead of during epilog generation.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice!

@forki
Copy link

forki commented Oct 8, 2021

backport this work to .NET 6

so what's the release train? thx

@jakobbotsch
Copy link
Member Author

so what's the release train? thx

It will be part of .NET 7 which is scheduled for end of next year. There are (unsupported) SDKs at https://github.com/dotnet/installer#installers-and-binaries that already should contain this change in case you wish to play around with it.

@ghost ghost locked as resolved and limited conversation to collaborators Nov 7, 2021
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
area-CodeGen-coreclr CLR JIT compiler in src/coreclr/src/jit and related components such as SuperPMI
Projects
None yet
Development

Successfully merging this pull request may close these issues.

[JIT][arm64] CSE for VSD calls
10 participants