GCC のドキュメントを読みましたか?
組み込み関数: long __builtin_expect (long exp, long c)
__builtin_expect を使用して、コンパイラに分岐予測情報を提供できます。一般に、これには実際のプロファイル フィードバック (-fprofile-arcs) を使用することをお勧めします。これは、プログラマーが自分のプログラムが実際にどのように動作するかを予測するのが苦手なことで知られているためです。ただし、このデータを収集するのが難しいアプリケーションもあります。
戻り値は exp の値であり、整数式でなければなりません。組み込みのセマンティクスは、exp == c であることが期待されるということです。例えば:
if (__builtin_expect (x, 0))
foo ();
x が 0 であると予想されるため、foo を呼び出す必要がないことを示します。exp の整数式に制限されているため、次のような構造を使用する必要があります。
if (__builtin_expect (ptr != NULL, 1))
foo (*ptr);
ポインターまたは浮動小数点値をテストする場合。
これを少し説明すると... __builtin_expect は、プログラムがどのブランチを取る可能性が高いと思われるかを伝えるのに特に役立ちます。コンパイラがその洞察をどのように使用できるかを尋ねると、次のコードを検討してください。
if (x == 0)
return 10 * y;
else
return 39;
マシンコードでは、通常、CPU は別の行に「移動」するように要求できます (これには時間がかかり、CPU によっては、他の実行の最適化が妨げられる場合があります。つまり、マシンコードのレベルの下にあります。たとえば、httpの下のブランチの見出しを参照してください。 //en.wikipedia.org/wiki/Instruction_pipeline )、または他のコードを呼び出すことができますが、true と false の両方のコードが等しいという if/else の概念は実際にはありません...コードを見つけるために分岐する必要がありますどちらか一方。これを行う方法は、基本的に、疑似コードで次のとおりです。
test whether x is 0
if it was goto else_return_39
return 10 * y
else_return_39:
return 39
ほとんどの CPU は、単に にフォールスルーするよりもラベルに到達goto
するのが遅いため、「true」ブランチのコードは false ブランチのコードよりも速く到達します。もちろん、マシン コードは x が0 でないかどうかをテストし、最初に「偽」のコード ( ) を配置して、パフォーマンス特性を逆にすることができます。else_return_39:
return 10 * y
return 39
これは __builtin_expect が制御するものです。コンパイラーに true または false 分岐を配置するように指示することができ、そこに到達するのに必要な分岐が少なくてすみます。これにより、パフォーマンスがわずかに向上します。
しかし、これは a) インライン if、b) 変数、c) 0 と 1 以外の値に対して機能しますか?
a) 周囲の関数がインライン化されているかどうかによって、if
ステートメントが表示される場所での分岐の必要性は変わりません (オプティマイザーが、if
ステートメント テストが常に実行されるtrue
かfalse
、1 つの分岐のみが実行されないという条件を認識しない限り)。したがって、インライン コードにも同様に適用できます。
[ あなたのコメントは、あなたが条件式に興味を持っていたことを示してa ? b : c
います。さらなる探求の基礎]
b) 変数 - あなたが仮定した:
int x = __builtin_expect( t / 10, 7 );
if( x == 7 ) {
それはうまくいきません - コンパイラは、そのような期待を変数に関連付けて、次に anif
が見られたときにそれらを記憶する義務はありません。これを確認するには (gcc 3.4.4 で行ったように) を使用gcc -S
して、アセンブリ言語の出力を生成します。期待値に関係なく、アセンブリは変更されません。
c) 0 と 1 以外の値
整数 ( long
) 値で機能するので、そうです。上記のドキュメントの最後の段落では、具体的には次のように説明されています。
次のような構造を使用する必要があります
if (__builtin_expect (ptr != NULL, 1))
foo (*ptr);
ポインターまたは浮動小数点値をテストする場合。
なんで?ポインタの型が よりも大きい場合long
、呼び出し__builtin_conversion(long, long)
によって重要度の低いビットの一部が効果的に切り捨てられ、残りをテストに組み込むことができなくなります。同様に、浮動小数点値は long よりも大きい場合があり、変換によって期待どおりの結果が得られません。ptr != NULL
( true
converts to 1L and to 0)などのブール式を使用するとfalse
、意図した結果が確実に得られます。