3

MSVC ++コンパイラがコードを最適化できるか(コード例を含む)、または最適化できないものとその理由を疑問に思っています。

たとえば、私はこのようなものでSSE-intrinsicsを使用しました(varは__m128値です)(これは錐台カリングテスト用でした):

if( var.m128_f32[0] > 0.0f && var.m128_f32[1] > 0.0f && var.m128_f32[2] > 0.0f && var.m128_f32[3] > 0.0f ) {
    ...
}

asm-output を見てみると、醜い非常にびくびくしたバージョンにコンパイルされていることがわかりました (そして、CPU がタイトなジャンプを嫌うだけであることはわかっています)。また、SSE4.1 PTEST 命令で最適化できることもわかっています。 、しかし、なぜコンパイラーはそれをしなかったのですか?

どのような最適化も実行できません (今まで)。

これは、組み込みとインライン ASM およびリンクされた ASM 関数を使用することを余儀なくされた今日のテクノロジで、コンパイラがそのようなものを見つけることを意味しますか (私はそうは思いません)。

MSVC++ コンパイラの最適化の詳細については、どこで読むことができますか?

(編集 1): SSE2 スイッチと FP:fast スイッチを使用しました

4

5 に答える 5

4

コンパイラのデフォルトは、「最小公分母」の CPU、つまり SSE 4.1 命令のない CPU で実行されるコードを生成するように設定されています。

ビルドオプションでのみ後のCPUをターゲットにすることで、これを変更できます。

とはいえ、 SSE の最適化に関しては、MS コンパイラは伝統的に「最善ではない」と言えます。SSE 4 をサポートしているかどうかさえわかりません。そのリンクは、SSEの最適化のためにGCCに良い信用を与えます:

コード生成における GCC のほぼ完璧さについての余談ですが、Intel 独自のコンパイラをも凌駕していることに非常に驚きました。

おそらく、コンパイラを変更する必要があります!

于 2010-07-14T23:04:05.783 に答える
2

Intel の ICC コンパイラを試してみてください。私の経験では、特に SSE コードの場合、Visual C++ よりもはるかに優れたコードを生成します。intel.com から 30 日間無料の評価ライセンスを取得できます。

于 2010-07-14T22:28:46.323 に答える
1

コンパイルされたコードの asm ビューをアクティブにして、生成されたものを自分で確認できます。

于 2010-07-14T22:29:40.753 に答える
0

Ïf ステートメントは、条件付き移動を利用できない限り条件付きジャンプを生成しますが、それは手書きのアセンブリで行われる可能性が高いです。ルールに沿って動作する条件付きジャンプのペナルティが許容されるように、CPU の条件付きジャンプの仮定 (分岐予測) を管理するルールがあります。次に、物事をさらに複雑にするための順不同の実行があります:)。肝心なのは、コードが単純であれば、最終的に発生するジャンプによってパフォーマンスが台無しになることはないということです。Agner Fog の最適化ページをチェックしてみてください。

特に、C コードの非デバッグ コンパイルでは、4 つの条件付きジャンプが生成されるはずです。論理積 (&&) と括弧を使用すると、左から右へのテストが行​​われるため、C の最適化の 1 つは、最初に >0.0f である可能性が最も高い f32 をテストすることです (そのような確率が決定できる場合)。5 つの可能な実行バリアントがあります。

t1tbt                      ; var.m128_f32[0] <= 0.0f
t1fnb t2tbt                ; var.m128_f32[0] >  0.0f, var.m128_f32[1] <= 0.0f
t1fnb t2fnb t3tbt          ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] <= 0.0f
t1fnb t2fnb t3fnb t4tbt    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f,
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] <= 0.0f
t1fnb t2fnb t3fnb t4fnb    ; var.m128_f32[0] >  0.0f, var.m128_f32[1] >  0.0f
                           ; var.m128_f32[2] >  0.0f, var.m128_f32[3] >  0.0f

発生した分岐のみがパイプラインの中断を引き起こし、分岐予測は中断を可能な限り最小限に抑えます。

float はテストにコストがかかると仮定すると (実際にそうです)、var が共用体であり、浮動小数点のインとアウトに精通している場合は、オーバーラップする型で整数テストを行うことを検討できます。たとえば、格納された値 1.0f は、0x00、0x00、0x80、0x3f (x86/リトルエンディアン) として格納された 4 バイトを占有します。この値を長整数として読み取ると、0x3f800000 または +1065353216 が得られます。0.0f は 0x00、0x00、0x00、0x00 または 0x00000000 (ロング) です。負の float 値は、最上位ビットが設定されている (0x80000000) ことを除いて、正の値とまったく同じ形式です。

于 2011-04-14T08:23:32.237 に答える
0

http://lambda-the-ultimate.org/node/3674でプレゼンテーションを確認してください

概要: コンパイラは一般的に、末尾呼び出しの最適化など、一般的に命令型プログラミングに関連していないように見えるものでさえ、多くの驚くべきトリックを実行します。MSVC++ は最高ではありませんが、それでもかなり良いようです。

于 2010-07-14T22:46:44.500 に答える