[IL Emit] Improve analysis to reduce emit of tail.
- Dominant language
- F#
- Stars
- 4.3k
- Forks
- 876
- Avg merge
- 4d 11h
- Merged PRs (30d)
- 131
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:
``` il
.method public static int32
noTailCalls(
class [System.Collections]System.Collections.Generic.List`1 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 class [System.Collections]System.Collections.Generic.List`1::GetEnumerator()
IL_000c: call !!0/*int32*/ Tailcalls/GSeq::fold>(!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!2/*valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator*/)
IL_0011: ret
} // end of method Tailcalls::noTailCalls
```
```
.method public static int32
whyTailCalls(
class [System.Collections]System.Collections.Generic.List`1 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 class [System.Collections]System.Collections.Generic.List`1::GetEnumerator()
IL_000c: tail.
IL_000e: call !!0/*int32*/ [Lib.FSharp]Lib.FSharp.GenericEnumerators.GSeq::fold>(!!0/*int32*/, class [FSharp.Core]Microsoft.FSharp.Core.FSharpFunc`2>, !!2/*valuetype [System.Collections]System.Collections.Generic.List`1/Enumerator*/)
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
Contributor guide
Assessment
This issue has not been assessed yet.