-
Notifications
You must be signed in to change notification settings - Fork 849
Open
Labels
Area-Compiler-CodeGenIlxGen, ilwrite and things at the backendIlxGen, ilwrite and things at the backendFeature Improvement
Milestone
Description
https://github.com/En3Tho/RandomBenchmarks/blob/master/src/RandomBenchmarks/FSharpBenchmarks/UnexpectedTailCalls.fs - here is the benchmark with repro
There are 2 GSeq modules: first is in file with benchmark and second is in another project, but they basically have same code inside them
For some reason F# compiler emits no tailcalls (as expected) when calling GSeq functions from the same file
But it emits .tailcall prefix when calling same GSeq functions from another project
Examples:
.method public static int32
noTailCalls(
class [System.Collections]System.Collections.Generic.List`1<int32> list
) cil managed
{
.maxstack 8
// [29 8 - 29 17]
IL_0000: ldc.i4.0
IL_0001: ldsfld class Tailcalls/noTailCalls@29 Tailcalls/noTailCalls@29::@_instance
IL_0006: ldarg.0 // list
IL_0007: callvirt instance valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<!0/*int32*/> class [System.Collections]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000c: call !!0/*int32*/ Tailcalls/GSeq::fold<int32, int32, valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int32>>(!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!1/*int32*/, !!0/*int32*/>>, !!2/*valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int32>*/)
IL_0011: ret
} // end of method Tailcalls::noTailCalls
.method public static int32
whyTailCalls(
class [System.Collections]System.Collections.Generic.List`1<int32> list
) cil managed
{
.maxstack 8
// [34 8 - 34 47]
IL_0000: ldc.i4.0
IL_0001: ldsfld class Tailcalls/whyTailCalls@34 Tailcalls/whyTailCalls@34::@_instance
IL_0006: ldarg.0 // list
IL_0007: callvirt instance valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<!0/*int32*/> class [System.Collections]System.Collections.Generic.List`1<int32>::GetEnumerator()
IL_000c: tail.
IL_000e: call !!0/*int32*/ [Lib.FSharp]Lib.FSharp.GenericEnumerators.GSeq::fold<int32, int32, valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int32>>(!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2<!!1/*int32*/, !!0/*int32*/>>, !!2/*valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator<int32>*/)
IL_0013: ret
} // end of method Tailcalls::whyTailCalls
Unexpected tailcall makes function run 2-3 times slower and blows asm size 2x because of additional tailcall dispatch helpers being generated by jit
Reactions are currently unavailable
Metadata
Metadata
Assignees
Labels
Area-Compiler-CodeGenIlxGen, ilwrite and things at the backendIlxGen, ilwrite and things at the backendFeature Improvement
Type
Projects
Status
New