In below code. If I want to access individual bit of the variable and compare it with 1. Like cmp ax,1 and keep increment the location of bit by 1 to get next bit, so that I can calculate the number of bits set to 1 in that variable. Is that possible?
.data
var dw 1234
.code
CodePudding user response:
It's not exactly clear, if you are targeting 16-bit or 32-bit architectures.
The typical way to count bits one by one would be something like:
mov cx, 1 // set mask bit
mov bx, 0 // initialise counter to accumulate bits
next_bit:
test ax, cx // check if the current bit is set, ZF==1 if not
jz skip_increment // if ZF==1, do not increment
inc bx
skip_increment:
add cx, cx // shift CX left by addition (8000h 8000h will overflow to zero)
jnz next_bit // if the mask did not yet overflow, continue loop
This fragment already has many optimisations:
- we don't need to calculate
1 << j
, - nor we need to have an iteration count
j
- overflow of (0x8000 << 1) == 0, which is detected when jumping to loop beginning
If we are willing to trash ax
, we can instead shift ax
right, with the benefit that we can jump off the loop immediately when there are no more bits in ax
to count.
mov cx, 0
next_bit: test ax, 1
jz skip_increment
inc cx
skip_increment:
shr ax, 1
jnz next_bit
Can we do better? It does not look efficient that we need to jump forward to skip the increment.
xor cx, cx // another way to clear the counter register
next_bit:
shr ax, 1 // shift out the LSB in ax to carry
adc cx, 0 // increment with carry
test ax, ax // now we need to re-test ax for zero
jnz next_bit
Oddly enough x86 instruction set contains jcxz
- jump if cx==0, but not the opposite: jump if cx != 0. If it did, we could swap the meaning of ax and cx and jump to beginning of loop without additional test.
But we can still rearrange the loop so, that we duplicate some code to allow the loop to process elements both from previous and current iteration.
sub cx, cx // another way to clear cx, but also ensure CF==0
next_bit:
adc cx, 0 // add the carry from previous iteration
shr ax, 1 // move the LSB to carry, sets ZF, iff ax==0
jnz next_bit
adc cx, 0 // add the carry from last iteration