Creating a mask with N least significant bits set

前端 未结 6 1738
离开以前
离开以前 2021-01-18 01:00

I would like to create a macro or function1 mask(n) which given a number n returns an unsigned integer with its n least sig

6条回答
  •  难免孤独
    2021-01-18 01:22

    When the input N is between 1 and 64, we can use -uint64_t(1) >> (64-N & 63).
    The constant -1 has 64 set bits and we shift 64-N of them away, so we're left with N set bits.

    When N=0, we can make the constant zero before shifting:

    uint64_t mask(unsigned N)
    {
        return -uint64_t(N != 0) >> (64-N & 63);
    }
    

    This compiles to five instructions in x64 clang. The neg instruction sets the carry flag to N != 0 and the sbb instruction turns the carry flag into 0 or -1. The shift length 64-N & 63 was optimized to -N: the shr instruction already has an implicit shift_length & 63.

    mov rcx,rdi
    neg rcx
    sbb rax,rax
    shr rax,cl
    ret
    

    With the BMI2 extension, it's only four instructions (the shift length can stay in rdi):

    neg edi
    sbb rax,rax
    shrx rax,rax,rdi
    ret
    

提交回复
热议问题