This code:
```zig
export fn foo(a: u64) u64 {
return ~blsmsk(a);
}
fn blsmsk(a: u64) u64 {
return (a ^ (a - 1));
}
```
Gives this emit:
```asm
foo:
mov rax, rdi
neg rax
xor rax, rdi
ret
```
With inline assembly, we can force the compiler to do the thing we want:
```zig
export fn bar(a: u64) u64 {
return ~blsmsk_asm(a);
}
inline fn blsmsk_asm(src: u64) u64 {
return asm ("blsmsk %[src], %[ret]"
: [ret] "=r" (-> u64),
: [src] "r" (src),
);
}
```
```asm
bar:
blsmsk rax, rdi
not rax
ret
```
In my real code, I was doing a bitwise AND on `~blsmsk(a)`. Meaning the `not` can be folded into an `ANDN` instruction.
```zig
export fn foo(a: u64, b: u64) u64 {
return ~blsmsk(a) & b;
}
```
```asm
foo:
mov rax, rdi
neg rax
xor rax, rdi
and rax, rsi
ret
```
Again, with inline assembly, we can get:
```asm
bar:
blsmsk rax, rdi
andn rax, rax, rsi
ret
```
[Godbolt link](https://zig.godbolt.org/z/GMcf56rj7)
This code:
Gives this emit:
With inline assembly, we can force the compiler to do the thing we want:
In my real code, I was doing a bitwise AND on
~blsmsk(a)
. Meaning thenot
can be folded into anANDN
instruction.Again, with inline assembly, we can get:
Godbolt link