if we are talking about C and blah is not within your control, then just do this:
if(blah) number += (1<<n);
There is really not a boolean in C and does not need to be, false is zero and true is not zero, so you cannot assume that not zero is 1 which is what you would need for your solution, nor can you assume that any particular bit in blah is set, for example:
number += (blah&1)<<n;
Would not necessarily work either because 0x2 or 0x4 or anything non-zero with bit zero clear is considered a true. Typically you will find 0xFFF...FFFF (minus one, or all ones) used as true, but you cannot rely on typical.
Now, if you are in complete control over the value in blah, and keep it strictly to a 0 for false and 1 for true then you could do what you were asking about:
number += blah<<n;
And avoid the potential for a branch, extra cache line fill, etc.
Back to the generic case though, taking this generic solution:
unsigned int fun ( int blah, unsigned int n, unsigned int number )
{
if(blah) number += (1<<n);
return(number);
}
And compiling for the two most popular/used platforms:
testl %edi, %edi
movl %edx, %eax
je .L2
movl $1, %edx
movl %esi, %ecx
sall %cl, %edx
addl %edx, %eax
.L2:
The above uses a conditional branch.
The one below uses conditional execution, no branch, no pipeline flush, is deterministic.
cmp r0,#0
movne r3,#1
addne r2,r2,r3,asl r1
mov r0,r2
bx lr
Could have saved the mov r0,r2 instruction by re-arranging the arguments in the function call, but that is academic, you wouldnt burn a function call on this normally.
EDIT:
As suggested:
unsigned int fun ( int blah, unsigned int n, unsigned int number )
{
number += ((blah!=0)&1)<<n;
return(number);
}
subs r0, r0, #0
movne r0, #1
add r0, r2, r0, asl r1
bx lr
Certainly cheaper, and the code looks good, but I wouldnt make assumptions that the result of blah!=0, which is zero or whatever the compiler has defined as true always has the lsbit set. It doesnt have to have that bit set for the compiler to generate working code. Perhaps the standards dictate the specific value for true. by re-arranging the function parameters the if(blah) number +=... will also result in three single clock instructions and not have assumptions.
EDIT2:
Looking at what I understand to be the C99 standard:
The == (equal to) and != (not equal
to) operators are analogous to the
relational operators except for their
lower precedence. Each of the
operators yields 1 if the specified
relation is true and 0 if it is false.
Which explains why the above edit works and why you get the movne r0,#1 and not some other random number.
The poster was asking the question with regards to C but also noted that ADA was the current language, from a language independent perspective you should not assume "features" like the C feature above and use an if(blah) number = number + (1<<n). But this was asked with a C tag so the generically (processor independent) fastest result for C is, I think, number += (blah!=0)<<n; So Steven Wright's comment had it right and he should get credit for this.
The posters assumption is also basically correct, if you can get blah into a 0 or 1 form then using it in the math is faster in the sense that there is no branch. Getting it into that form without it being more expensive than a branch is the trick.
_Bool
, aliased tobool
instdbool.h
. Also, while any nonzero value counts as true for conditionals, the result of a boolean expression (comparison operators, logical and/or/not operators, ...) is always 0 or 1. – Ashyblah*2^n
isblah<<n
(bit-shift) and one of the fastest possible operations. – Ashy