Skip to content

[x86-64 BMI2] Missed canonicalization on ~blsmsk #103501

@Validark

Description

@Validark

This code:

export fn foo(a: u64) u64 {
    return ~blsmsk(a);
}

fn blsmsk(a: u64) u64 {
    return (a ^ (a - 1));
}

Gives this emit:

foo:
        mov     rax, rdi
        neg     rax
        xor     rax, rdi
        ret

With inline assembly, we can force the compiler to do the thing we want:

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),
    );
}
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.

export fn foo(a: u64, b: u64) u64 {
    return ~blsmsk(a) & b;
}
foo:
        mov     rax, rdi
        neg     rax
        xor     rax, rdi
        and     rax, rsi
        ret

Again, with inline assembly, we can get:

bar:
        blsmsk  rax, rdi
        andn    rax, rax, rsi
        ret

Godbolt link

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions