1.22. MANIPULATING SPECIFIC BIT(S)
BIC R3, R2, #0x80000000
; copy from R3 to S0:
FMSR S0, R3
BX LR
set_sign
; copy from S0 to R2:
FMRS R2, S0
; do OR:
ORR R3, R2, #0x80000000
; copy from R3 to S0:
FMSR S0, R3
BX LR
negate
; copy from S0 to R2:
FMRS R2, S0
; do ADD:
ADD R3, R2, #0x80000000
; copy from R3 to S0:
FMSR S0, R3
BX LR
Let’s run Raspberry Pi Linux in QEMU and it emulates an ARM FPU, so S-registers are used here for floating
point numbers instead of R-registers.
TheFMRSinstruction copies data fromGPRto the FPU and back.
my_abs()andset_sign()looks as expected, but negate()? Why is thereADDinstead ofXOR?
It’s hard to believe, but the instructionADD register, 0x80000000works just like
XOR register, 0x80000000. First of all, what’s our goal? The goal is to flip theMSB, so let’s forget
about theXORoperation. From school-level mathematics we may recall that adding values like 1000 to
other values never affects the last 3 digits. For example:1234567 + 10000 = 1244567(last 4 digits are never
affected).
But here we operate in binary base and
0x80000000 is 0b100000000000000000000000000000000, i.e., only the highest bit is set.
Adding 0x80000000 to any value never affects the lowest 31 bits, but affects only theMSB. Adding 1 to
0 is resulting in 1.
Adding 1 to 1 is resulting in 0b10 in binary form, but the 32th bit (counting from zero) gets dropped,
because our registers are 32 bit wide, so the result is 0. That’s whyXORcan be replaced byADDhere.
It’s hard to say why GCC decided to do this, but it works correctly.
1.22.5 Counting bits set to 1.
Here is a simple example of a function that calculates the number of bits set in the input value.
This operation is also called “population count”^151.
#include <stdio.h>
#define IS_SET(flag, bit) ((flag) & (bit))
int f(unsigned int a)
{
int i;
int rt=0;
for (i=0; i<32; i++)
if (IS_SET (a, 1<<i))
rt++;
return rt;
};
(^151) modern x86 CPUs (supporting SSE4) even have a POPCNT instruction for it