5

/fp:precise/fp:fastフラグを使用するコードを調べていました。

のMSDNドキュメントによると/fp:precise

x86 プロセッサで /fp:precise を使用すると、コンパイラは float 型の変数に対して、代入とキャスト、および関数にパラメーターを渡すときに、適切な精度に丸めを実行します。この丸めにより、データがその型の容量を超える重要性を保持しないことが保証されます。/fp:precise を使用してコンパイルされたプログラムは、/fp:precise を使用せずにコンパイルされたプログラムよりも遅く、サイズが大きくなる可能性があります。/fp:precise は組み込み関数を無効にします。代わりに、標準のランタイム ライブラリ ルーチンが使用されます。詳細については、「/Oi (組み込み関数の生成)」を参照してください。

sqrtf(/arch:SSE2ターゲットx86/Win32プラットフォームで呼び出される)への呼び出しの逆アセンブリを見ると、次のようになります。

0033185D  cvtss2sd    xmm0,xmm1  
00331861  call        __libm_sse2_sqrt_precise (0333370h)  
00331866  cvtsd2ss    xmm0,xmm0  

この質問から、最新の x86/x64 プロセッサは 80 ビット レジスタを使用しない (または少なくともその使用を思いとどまらせる) ため、コンパイラは次善の策と思われることを実行し、64 ビット double を使用して計算を行うと考えています。また、組み込み関数が無効になっているため、ライブラリ sqrtf 関数への呼び出しがあります。

わかりました、これはドキュメントの内容に準拠しているようです。

ただし、x64 arch 用にコンパイルすると、奇妙なことが起こります。

000000013F2B199E  movups      xmm0,xmm1  
000000013F2B19A1  sqrtps      xmm1,xmm1  
000000013F2B19A4  movups      xmmword ptr [rcx+rax],xmm1  

計算は 64 ビット double では実行されず、組み込み関数が使用されています。私が知る限り、結果は/fp:fastフラグを使用した場合とまったく同じです。

両者の間に食い違いがあるのはなぜですか?/fp:precisex64 プラットフォームでは動作しませんか?

ここで、サニティ チェックとして、VS2010 x86 で/fp:preciseと を使用して同じコードをテストしました/arch:SSE2。驚いたことに、sqrtpd組み込み関数が使用されていました。

00AF14C7  cvtps2pd    xmm0,xmm0  
00AF14CA  sqrtsd      xmm0,xmm0  
00AF14CE  cvtpd2ps    xmm0,xmm0 

何が起きてる?VS2012 がシステム ライブラリを呼び出すのに、VS2010 が組み込み関数を使用するのはなぜですか?

x64 プラットフォームを対象とした VS2010 のテストでは、VS2012 と同様の結果が得られます (/fp:precise無視されているようです)。

古いバージョンの VS にアクセスできないため、これらのプラットフォームでテストを行うことはできません。

参考までに、Intel i5-m430 プロセッサを搭載した Windows 7 64 ビットでテストしています。

4

1 に答える 1

3

まず最初に、中間浮動小数点精度に関するこの非常に優れたブログ投稿を読む必要があります。この記事では、Visual Studio で生成されたコードのみを扱います (ただし、それがあなたの質問のすべてです)。それでは例を見てみましょう:

0033185D  cvtss2sd    xmm0,xmm1  
00331861  call        __libm_sse2_sqrt_precise (0333370h)  
00331866  cvtsd2ss    xmm0,xmm0  

このアセンブラ コードは/fp:precise /arch:SSE2、x86 プラットフォーム用に生成されています。ドキュメントによると、正確な浮動小数点モデルにより、x86 プラットフォームではすべての計算が内部的に倍増します。また、組み込み関数の使用を防ぎます (この情報は既に読んでいると思います)。したがって、コードは float から double への変換から始まり、倍精度の sqrt 呼び出しが続き、最後に結果が float に変換されます。

000000013F2B199E  movups      xmm0,xmm1  
000000013F2B19A1  sqrtps      xmm1,xmm1  
000000013F2B19A4  movups      xmmword ptr [rcx+rax],xmm1

2 番目の例は x64 (amd64) プラットフォーム用にコンパイルされており、このプラットフォームの動作はまったく異なります! ドキュメントによると:

パフォーマンス上の理由から、中間操作は、使用可能な最大精度ではなく、いずれかのオペランドの最大精度で計算されます。

したがって、計算は内部的に単精度で行われます。また、可能な限り組み込み関数を使用することを決定したと思うので、x64 プラットフォームで/fp:preciseはとの差/fp:fastはやや小さくなります。新しい動作によりコードが高速になりプログラマーは正確に何が起こるかをより細かく制御できるようになります (互換性の問題は新しい x64 プラットフォームでは問題にならなかったため、プログラマーはゲームのルールを変更することができました)。残念ながら、これらの変更/相違点はドキュメントに明示的に記載されていません。

00AF14C7  cvtps2pd    xmm0,xmm0  
00AF14CA  sqrtsd      xmm0,xmm0  
00AF14CE  cvtpd2ps    xmm0,xmm0 

最後に、最後の例は Visual Studio 2010 コンパイラでコンパイルされており、(少なくとも/fp:preciseモードでは) 使用しないほうがよい場合に、誤って sqrt の組み込みを使用したと思いますが、Visual Studio 2012 でこの動作を変更/修正することにしました。再び(ここを参照)。

于 2013-05-22T12:25:42.903 に答える