I have a value int x
where I want to conditionally add (for example) a value int y
to, contingent on bool c
. I could write code like this:
bool c; // C23, or stdbool.h macro for _Bool. Converts to integer 0 or 1
int x, y; // x could be a global or something
...
if (c)
x += y;
How could I write this without a branch?
If x
is a local variable that no other thread could have a reference to, compilers may do if-conversion to branchless if they think that's more efficient. (Especially if auto-vectorizing, but also for scalar.) But that wouldn't be thread-safe for global variables, or if x
is actually *x
with an int *
. Compilers can't invent writes like *x += 0
to possibly-shared objects that the abstract machine doesn't read or write, that could introduce a data race and step on values stored by other threads.
A basic answer would be to produce a branchless expression that evaluates to y
if c
is true
or to the identity of the operation (0 for addition/subtraction and 1 for multiplication/division) otherwise and then use that expression.
A very simple solution is simply multiply the boolean with y
then add:
x += c*y;
Create a mask from the boolean, bitwise and, then add:
x += -c&y;
This way, if the boolean is false, negating the value will still be 0, and bitwise and 0 with any number gives zero, so this will result in adding 0 to the value. Otherwise, negating true
would give -1
which is all 1s in 2's complement, which would give the y
back from the bitwise and, adding y
to x
.
Note: The question uses addition as an example, but if the operation in question is division or multiplication, the value !c
must be added to the right-hand operand of the augmented assignment. This is because the multiplicative identity is 1 and not 0.
E.g.
x *= -c&y+!c;