プロセッサのパイプライン化の実装方法が原因で分岐命令が非常にコストがかかる特定のアーキテクチャのコンパイル済みアセンブリコードで、分岐命令の数を最小限に抑えようとしています。
条件分岐で条件をテストする必要がある回数を減らすために自己変更コードを実装することを試みることができますが、他に何かできることはありますか?
コンパイルされたコードに表示される分岐命令の数についてはあまり気にする必要はありません。プログラムを実行するときに、CPUで分岐命令が実行される回数に注意する必要があります。
実行されるブランチの数を減らす2つの簡単な方法:
アーキテクチャが述語命令をサポートしている場合if
は、ブランチの代わりに述語命令を使用して小さなブロックを生成できます。コンパイラにこれを行うように依頼することができます。たとえば、コンパイラがGCCの場合は、でコンパイルする-O1, -O2, -O3 or -Os
か、-fif-conversion2
フラグを使用してこれを行う必要があります。次の点に注意してください。条件が真であるかどうかに関係なく、述語命令がCPUパイプラインを通過するため、
大きなブロックは変換されません。if
そして、これはサイクルを無駄にします。
ループを展開します。ループは分岐を意味します。それを展開すると、実行する分岐の数を減らすことができます(ただし、コンパイルされたコードでは、同じ数の分岐命令が表示されますよね?)。
ただし、覚えておいてください。これにより、コードサイズが大きくなります。これは、命令キャッシュのミス率の増加を意味する可能性があります。
例えば:
for (i = 0; i < N; i++)
{
LOOP_BODY;
}
Nが偶数であることがわかっている場合、手動で2回展開するのは次のように簡単です。
for (i = 0; i < N; i++)
{
LOOP_BODY;
i++;
LOOP_BODY;
}
これを実行すると、実行されるブランチの数は基本的に半分になります。
繰り返しますが、コンパイラはおそらくこれを自動的に行うこともできます。たとえば、GCCは。を使用していくつかのループを展開します-funroll-loops
。
コンパイラがあなたのためにできる他のいくつかのトリックがあります。たとえば、GCCの場合は、おそらくこのページで「branch」を検索する必要があります。