Sometimes F# doesn't inline functions even if it is marked `inline`?

孤人 提交于 2020-01-03 16:36:46

问题


let inline funA x =
    printf "A"
    x > 3

let inline funB myFun x =
    printf "B"
    myFun x

let foo () =
    funB funA 7

IL for foo

.method public static 
    bool foo () cil managed 
{
    // Method begins at RVA 0x2278
    // Code size 31 (0x1f)
    .maxstack 4
    .locals init (
        [0] class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>
    )

    IL_0000: nop
    IL_0001: ldstr "B"
    IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
    IL_000b: stloc.0
    IL_000c: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()
    IL_0011: ldloc.0
    IL_0012: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatToTextWriter<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
    IL_0017: pop
    IL_0018: ldc.i4.7
    IL_0019: call bool Foo::myFun@21(int32)  // Here!
    IL_001e: ret
} // end of method Foo::foo

IL for myFun@21

    .method assembly static 
        bool myFun@21 (
            int32 x
        ) cil managed 
    {
        .custom instance void [mscorlib]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
            01 00 00 00
        )
        // Method begins at RVA 0x224c
        // Code size 29 (0x1d)
        .maxstack 4
        .locals init (
            [0] class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>
        )

        IL_0000: ldstr "A"
        IL_0005: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
        IL_000a: stloc.0
        IL_000b: call class [mscorlib]System.IO.TextWriter [mscorlib]System.Console::get_Out()
        IL_0010: ldloc.0
        IL_0011: call !!0 [FSharp.Core]Microsoft.FSharp.Core.PrintfModule::PrintFormatToTextWriter<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
        IL_0016: pop
        IL_0017: nop
        IL_0018: ldarg.0
        IL_0019: ldc.i4.3
        IL_001a: cgt
        IL_001c: ret
    } // end of method Foo::myFun@21

IL for funA

.method public static 
    bool funA (
        int32 x
    ) cil managed 
{
    // Method begins at RVA 0x2218
    // Code size 22 (0x16)
    .maxstack 8

    IL_0000: nop
    IL_0001: ldstr "A"
    IL_0006: newobj instance void class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`5<class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>::.ctor(string)
    IL_000b: call !!0 [FSharp.Core]Microsoft.FSharp.Core.ExtraTopLevelOperators::PrintFormat<class [FSharp.Core]Microsoft.FSharp.Core.Unit>(class [FSharp.Core]Microsoft.FSharp.Core.PrintfFormat`4<!!0, class [mscorlib]System.IO.TextWriter, class [FSharp.Core]Microsoft.FSharp.Core.Unit, class [FSharp.Core]Microsoft.FSharp.Core.Unit>)
    IL_0010: pop
    IL_0011: ldarg.0
    IL_0012: ldc.i4.3
    IL_0013: cgt
    IL_0015: ret
} // end of method Foo::funA

As you can see, myFun@21 is almost identical to funA, I don't get why it exists. Also why the function is not inlined? Is it because I passed a function as an argument into another function? In this case I don't think there is any hard to resolve closure thing to make it impossible to inline.

Are there any resources that I can learn more about when a function cannot be inlined though it is marked inline?


回答1:


I believe that the function was inlined, just not in the way that you expected. funA can only be inlined if it has an argument. Since you aren't providing an argument to funA at the point of use, the compiler treats it as fun x -> funA x and inlines funA there - so a lambda is created and it's as if you wrote:

let foo() = 
    printf "B"
    (fun x -> 
        printf "A"
        x > 3) 7    


来源:https://stackoverflow.com/questions/17912509/sometimes-f-doesnt-inline-functions-even-if-it-is-marked-inline

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!