This is how the C library function abs()
does it in assembly without branching:
abs(x) = (x XOR y) - y
where y = x >> 31
(assuming 32-bit input), and >>
is arithmetic right shift operator.
Explanation of the above formula:
We want to generate 2's complement of negative x
only.
y = 0xFFFFFFFF, if x is negative
0x00000000, if x is positive
So when x
is positive x XOR 0x00000000
is equal to x
. And when x
is negative x XOR 0xFFFFFFFF
is equal to 1's complement of x
. Now we just need to add 1
to get its 2's complement which is what expression -y
is doing . Because 0xFFFFFFFF
is -1 in decimal.
Let's look at assembly generated for following code by gcc
(4.6.3 on my machine):
C code:
main()
{
int x;
int output = abs(x);
}
gcc 4.6.3 generated assembly snippet (AT&T syntax), with my comments:
movl -8(%rbp), %eax # -8(%rbp) is memory for x on stack
sarl $31, %eax # shift arithmetic right: x >> 31, eax now represents y
movl %eax, %edx #
xorl -8(%rbp), %edx # %edx = x XOR y
movl %edx, -4(%rbp) # -4(%rbp) is memory for output on stack
subl %eax, -4(%rbp) # (x XOR y) - y
BONUS (from Hacker's Delight): If you have a fast multiply by +1 and -1, the following will give you abs(x)
for 32-bit x
:
((x >> 30) | 1) * x