9

私はこれに偶然出くわしました、そして私は少し戸惑っています。

.NET 4.0を対象とした、すべてのデフォルト設定を備えた、すぐに使用できるVS 2010 F#プロジェクトがあります。

F#コードは次のようになります。

let test(a:int, b:int, c:int) = min a (min b c)

リリース用にコンパイルすると、生成されたILには奇妙なNOP 命令が散らばっています。このような:

このために生成されたIL(すべてのデフォルト設定を使用):

.method public static int32  test(int32 a,
                                  int32 b,
                                  int32 c) cil managed
{
  // Code size       20 (0x14)
  .maxstack  4
  .locals init ([0] int32 V_0)

  // HERE
  IL_0000:  nop

  IL_0001:  ldarg.1
  IL_0002:  ldarg.2
  IL_0003:  bge.s      IL_0009
  IL_0005:  ldarg.1

  // HERE
  IL_0006:  nop

  IL_0007:  br.s       IL_000b
  IL_0009:  ldarg.2

  // HERE
  IL_000a:  nop

  IL_000b:  stloc.0
  IL_000c:  ldarg.0
  IL_000d:  ldloc.0
  IL_000e:  bge.s      IL_0012
  IL_0010:  ldarg.0
  IL_0011:  ret
  IL_0012:  ldloc.0
  IL_0013:  ret
} // end of method Module1::test

私の.fsprojプロジェクト構成は次のとおりです。

  <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
    <DebugType>pdbonly</DebugType>
    <Optimize>true</Optimize>
    <Tailcalls>true</Tailcalls>
    <OutputPath>bin\Release\</OutputPath>
    <DefineConstants>TRACE</DefineConstants>
    <WarningLevel>3</WarningLevel>
    <DocumentationFile>bin\Release\TestFsIL.XML</DocumentationFile>
  </PropertyGroup>

ここで、行をコメントアウトする<DebugType>pdbonly</DebugType>と、NOP指示が消えます。しかしもちろん、PDBファイルもそうです!

.method public static int32  test(int32 a,
                                  int32 b,
                                  int32 c) cil managed
{
  // Code size       17 (0x11)
  .maxstack  4
  .locals init (int32 V_0)
  IL_0000:  ldarg.1
  IL_0001:  ldarg.2
  IL_0002:  bge.s      IL_0007
  IL_0004:  ldarg.1
  IL_0005:  br.s       IL_0008
  IL_0007:  ldarg.2
  IL_0008:  stloc.0
  IL_0009:  ldarg.0
  IL_000a:  ldloc.0
  IL_000b:  bge.s      IL_000f
  IL_000d:  ldarg.0
  IL_000e:  ret
  IL_000f:  ldloc.0
  IL_0010:  ret
} // end of method Module1::test

行には微妙な違いもあります.locals

.locals init ([0] int32 V_0)

vs

.locals init (int32 V_0)

C#コンパイラを試したところNOP、デバッグビルドでのみ命令が生成されますが、を使用してPDBファイルが含まれている場合でも、リリースビルドでは命令が生成されないようです<DebugType>pdbonly</DebugType>

質問:

  1. C#でこれを回避できると思われるのに、PDBファイルが含まれている場合にリリースビルドのF#でNOP命令が生成されるのはなぜですか。

  2. それらのNOPを取り除く方法はありますが、それでもPDBファイルはありますか?

PS。ここここにSOに関する関連する質問がありますが、そこにあるすべての回答は

デバッグモードでコンパイルしている場合、リリースモードでコンパイルするとNOP

これは、示されているF#コンパイラでの私の経験と矛盾します。

4

1 に答える 1

8

これがF#コンパイラの内部でどのように機能するかは正確にはわかりませんが(F#チームの誰かがより良い答えを持っているかもしれません)、nop命令を生成することは、から参照できる場所を生成するための非常に簡単な方法だと思いますpdbファイル。

pdbファイルは、ブレークポイントを配置できるコードで式のIL範囲を指定する必要があります。これは、デバッグモードとリリースモードの両方に当てはまります。これは、ブレークポイントをどこかに配置する場合、IL内に対応する場所が必要であることを意味します。ただし、ソースコードの場所に対応する実際の命令がない場合、コンパイラは何かを挿入する必要があるため、を追加しますnop

リリースモードでは、F#コンパイラはさらに最適化を行いますがpdb、ファイルが必要な場合は、すべてのソースコードの場所を提供する必要があります。C#はソースILにより密接にマッピングされるため、これはC#では必要ない場合がありますが、F#ではこれを回避するのが難しい場合があります。

于 2012-04-13T10:51:19.860 に答える