5

コードの枝は

int value = //some number;
if(value > some_other_value)
   value *= 23;
else
   value -= 5; 

(コードの SIMD 最適化を有効にするため) ビットごとのマスキングを使用して削除できます。

const int Mask = (some_other_value-value)>>31;
value =      ((value * 23)&Mask)|((value-5)&~Mask);

ただし、これがどのように機能するかはわかりません (ここで使用されている操作と、結果がバイナリでどのように表示されるかは理解していますが)。さらに、これはどの程度一般的に適用できますか? 元のコードが代わりに次のようなものだったらどうなるでしょうか

if(value & 1 == 1)
   value *= 23;
else
   value -= 5;

ブランチを削除したコードは同じですか? それ以外の場合、マスクの目的は何ですか?また、マスクを作成するにはどうすればよいですか? ここで何が起きてるの?

4

2 に答える 2

4

これは機能します:

const int Mask = (some_other_value-value)>>31;
value =      ((value * 23)&Mask)|((value-5)&~Mask);

some_other_value - valueマスクは次のような-の符号ビットになります。

if (value > some_other_value) mask = -1; else mask = 0; 

次の例を使用して、2番目の例でも同じことを実現できます。

mask = -(value & 1);

したがって、-0 = 0、-1=すべてのものです。

編集:計算が複雑になりすぎると、特に分岐が合理的に予測可能である場合は特に、分岐バージョンでは何も得られないことも覚えておいてください。

于 2013-01-29T14:07:40.747 に答える
0

これは、最良の場合は時期尚早の最適化であり、最悪の場合は非最適化です。

コードをベクトル化できる場合、SIMD は他に何も知らないため、とにかく条件付き移動を使用します。

しかし、スカラー コードの場合でも、最新のコンパイラは通常、条件付き移動を生成するため、分岐はありません (両方の方程式を評価するのに十分なコストがかかり、分岐する方が効率的であるとコンパイラが判断しない限り)。

条件付き移動は、RISC プロセッサ (ARM など) の標準機能であり、x86 でも約 17 年間サポートされています。最新のプロセッサでは、条件付き移動は通常の移動とまったく同じ量のサイクル、または多くても 2 ~ 3 サイクル余分にかかります。
これは明らかに、条件が十分に早期に評価されることを前提としています (ただし、順不同で実行すると値が非表示になるため、値に依存性がなくても問題ありません)。も適用します。まだ存在しない結果を使用することはできません。

あなたがそれを助けることができるなら、難読化されたコードではなく、常に一目で理解できるコードを書いてください。

value = (((foo<<31)&bar, ++baz) -= (foo & 7121)) + PHASE_OF_MOON;

どれも速くないし遅くなる可能性が高いだけでなく、あなたのコードをレビューしている誰か (今から 6 ~ 10 か月後のあなた自身も含めて!) を混乱させるようなものは、非常に移植性が低く、誤った結果をもたらす可能性が非常に高くなります。予期しない状況。

于 2013-01-30T13:56:05.623 に答える