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
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