代码之家  ›  专栏  ›  技术社区  ›  Brian Rasmussen

F代码发布版本中的NOP

  •  6
  • Brian Rasmussen  · 技术社区  · 15 年前

    我在VS2010 Beta2中使用f,由于我对f还不熟悉,所以我选择了一个常见的示例,并实现了一个阶乘函数:

    let rec factorial n =
      if n <= 1 then 1 else n * factorial (n - 1);;
    

    如果我构建这个并在reflector中查看生成的代码,就会得到相应的c代码:

    public static int Factorial(int n) {
       if (n <= 1) 
          return 1;
    
          return n * Factorial(n - 1);
    }
    

    所以如果我编译reflector的f代码的c表示,我会得到相同的il。

    但是,如果我在发布模式下编译这两个代码片段并比较生成的IL,它们是不同的(功能相同,但仍有一点不同)。

    C实现编译为:

    .method public hidebysig static int32 Factorial(int32 n) cil managed
    {
       .maxstack 8
       L_0000: ldarg.0 
       L_0001: ldc.i4.1 
       L_0002: bgt.s L_0006
       L_0004: ldc.i4.1 
       L_0005: ret 
       L_0006: ldarg.0 
       L_0007: ldarg.0 
       L_0008: ldc.i4.1 
       L_0009: sub 
       L_000a: call int32 TestApp.Program::Factorial(int32)
       L_000f: mul 
       L_0010: ret 
    }
    

    f实现编译为:

    .method public static int32 factorial(int32 n) cil managed
    {
       .maxstack 5        <=== Different maxstack
       L_0000: nop        <=== nop instruction?
       L_0001: ldarg.0 
       L_0002: ldc.i4.1 
       L_0003: bgt.s L_0007
       L_0005: ldc.i4.1 
       L_0006: ret 
       L_0007: ldarg.0 
       L_0008: ldarg.0 
       L_0009: ldc.i4.1 
       L_000a: sub 
       L_000b: call int32 FSharpModule::factorial(int32)
       L_0010: mul 
       L_0011: ret 
    }
    

    生成的代码是相同的,除了不同的maxstack和f方法中附加的nop指令。

    这可能并不重要,但我很好奇为什么f编译器会在发布版本中插入nop。

    谁能解释为什么?

    (我非常清楚f编译器并没有经历与c编译器相同的实际测试级别,但这一点非常明显,我认为它会被捕获)。

    edit:compile命令如下

    C:\Program Files\Microsoft F#\v4.0\fsc.exe -o:obj\Release\FSharpLib.dll 
    --debug:pdbonly --noframework --define:TRACE --optimize+ 
    --target:library --warn:3 --warnaserror:76 --vserrors --utf8output --fullpaths 
    --flaterrors "C:\Temp\.NETFramework,Version=v4.0.AssemblyAttributes.fs" Module1.fs 
    

    (为简洁起见,删除了引用的程序集)。

    1 回复  |  直到 15 年前
        1
  •  17
  •   Jb Evain    15 年前

    maxstack的区别是因为c编译器编译第一个带有轻量级方法体头的方法,只要代码很小,没有异常,也没有局部变量,就使用轻量级方法体头。在这种情况下,没有指定maxstack,默认为8。

    f编译器正在使用«fat»方法体头,并指定它计算的maxstack。

    至于nop,这是因为您正在调试模式下编译。他们总是用nop启动方法体。见fsharp/ilxgen.ml:

    // Add a nop to make way for the first sequence point. There is always such a 
    // sequence point even when zapFirstSeqPointToStart=false
    do if mgbuf.cenv.generateDebugSymbols  then codebuf.Add(i_nop);
    

    如果我编译你的阶乘时没有调试符号,我就得不到nop。