Check if a number is even

后端 未结 2 1552
后悔当初
后悔当初 2021-01-28 18:23

I\'m working my way through low level bit hacks, and would like to write an assembly program for each. Here is what I have for checking if a number is even or not:



        
2条回答
  •  耶瑟儿~
    2021-01-28 18:48

    I can't get it down to two instructions, but I can golf it a little shorter.

    Your current version is 12 bytes including the ret. You can shave off two bytes with test $1, %dil instead, since the high bytes of the input are irrelevant, thus trading the 4-byte immediate for a 1-byte immediate and a prefix byte. That gets it down to 10.

    You can shave off two more bytes by taking advantage of the somewhat obscure fact that the shift instructions shift into the carry flag, and doing

    is_even: // 8 bytes
        xor %eax, %eax
        shr $1, %edi
        setnc %al
        ret
    

    gcc and clang both do

    is_even: // 8 bytes
        mov %edi, %eax
        not %eax
        and $1, %eax
        ret
    

    For one less byte, there's

    is_even: // 7 bytes
        shr $1, %edi
        sbb %eax, %eax
        inc %eax
        ret
    

    sbb is "subtract with borrow", which subtracts one register from another, then subtracts 1 more if the carry flag was set. This leaves us with 0 if the input was even, and -1 if it was odd. Then adding 1 gets us where we want to be. This might be slower because I'm not sure if the CPU knows that the result does not depend on the previous value of %eax.

    I don't see a way to get down to two instructions, though. It's an annoying feature of the conditional setcc instructions that they only set the low byte and leave the rest of the register alone, forcing you to zero it yourself in the common case that you want your boolean in the full register. And we have to get the input and output in two different registers, which is awkward because of x86's model where the output register is always one of the inputs.

提交回复
热议问题