I was told that the branches in the code
int value = //some number;
if(value > some_other_value)
value *= 23;
else
value -= 5;
can be eliminated via bitwise masking (in order to enable SIMD optimization for the code):
const int Mask = (some_other_value-value)>>31;
value = ((value * 23)&Mask)|((value-5)&~Mask);
However, I do not understand how this works (even though I understand what operations are being used here and how the results will look in binary). Furthermore, how generally applicable is this? What if the original code was instead something like
if(value & 1 == 1)
value *= 23;
else
value -= 5;
Would the branch-removed code still be the same? Otherwise, what is the purpose of the mask and how should I go about creating it? What is happening here?
This works:
const int Mask = (some_other_value-value)>>31;
value = ((value * 23)&Mask)|((value-5)&~Mask);
Mask becomes the sign bit of some_other_value - value
- similar to:
if (value > some_other_value) mask = -1; else mask = 0;
You could achieve the same thing with your second example, using:
mask = -(value & 1);
So, -0 = 0, -1 = all ones.
Edit: I would also bear in mind that if the calculation gets too complicated, you are not gaining anything over the branching version, particularly not if the branches are reasonably predictable.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With