GCCコンパイラは、可能性のあるマクロと可能性の低いマクロを定義するために使用される__builtin_expectステートメントをサポートします。
例えば。
#define likely(expr) (__builtin_expect(!!(expr), 1))
#define unlikely(expr) (__builtin_expect(!!(expr), 0))
Microsoft Visual Cコンパイラと同等のステートメント、または同等のものはありますか?
そのようなものはありません。 __ assume() がありますが、使用しないでください。これは別の種類のオプティマイザディレクティブです。
実際、gnuビルトインがマクロにラップされている理由は、__GNUC__
が定義されていない場合に自動的にそれを取り除くことができるようにするためです。これらのマクロについて必要なことは何もありません。実行時の違いに気付かないでしょう。
非GNUの*likely
を削除するだけです(nullアウト)。あなたはそれを見逃すことはありません。
http://www.akkadia.org/drepper/cpumemory.pdf (57ページ)によると、CPUが動的に正しく予測する場合でも、静的分岐予測を使用することは理にかなっています。その理由は、静的予測が正しく行われた場合、L1iキャッシュがさらに効率的に使用されるためです。
C++ 20標準には、[[likely]]
および[[unlikely]]
分岐予測属性が含まれます。
属性提案の最新リビジョンは http://wg21.link/p0479 から見つけることができます
元の属性の提案は http://www.open-std.org/jtc1/sc22/wg21/docs/papers/2016/p0479r0.html から見つけることができます。
プログラマーはPGOを好むべきです。属性は、正しく適用されなかったり、後でプログラムが変更されたときに正しくなくなったりすると、パフォーマンスが簡単に低下する可能性があります。
__ assume 類似している必要があります。
ただし、これを本当にうまくやりたい場合は、静的なヒントではなく、 プロファイルガイド付き最適化 を使用する必要があります。
誤予測を防ぐためのブランチとループの再編成 Intelのドキュメントによると:
これらのルールを利用するコードを効果的に作成するには、if-elseまたはswitchステートメントを作成するときに、最も一般的なケースを最初に確認し、最も一般的でないケースまで徐々に作業を進めていきます。
残念ながら、次のようなものを書くことはできません
#define if_unlikely(cond) if (!(cond)); else
vS10以降のMSVCオプティマイザーはそのような「ヒント」を無視するためです。
私は自分のコードで最初にエラーを処理することを好むので、効率の悪いコードを書くようです。幸い、CPUがブランチに2回目に遭遇すると、静的ヒントの代わりに統計を使用します。