Rust 编译器没有优化 lzcnt? (和类似的功能)

Posted

技术标签:

【中文标题】Rust 编译器没有优化 lzcnt? (和类似的功能)【英文标题】:Rust compiler not optimising lzcnt? (and similar functions) 【发布时间】:2021-12-25 16:24:30 【问题描述】:

做了什么:

这是在 Compiler Explorer 上进行实验的结果,以确定编译器 (rustc) 在涉及 log2()/leading_zeros() 和类似函数时的行为。我发现这个结果似乎非常奇怪和令人担忧:

Compiler Explorer link

代码:

pub fn lzcnt0(val: u64) -> u64 
    val.leading_zeros() as u64


pub unsafe fn lzcnt1(val: u64) -> u64 
    core::arch::x86_64::_lzcnt_u64(val)


pub unsafe fn lzcnt2(val: u64) -> u64 
    asm_lzcnt(val)


#[inline]
pub unsafe fn asm_lzcnt(val: u64) -> u64 
    let lzcnt: u64;
    core::arch::asm!("lzcnt , ", in(reg) val, lateout(reg) lzcnt, options(nomem, nostack));
    lzcnt

输出:

example::lzcnt0:
        test    rdi, rdi
        je      .LBB0_2
        bsr     rax, rdi
        xor     rax, 63
        ret
.LBB0_2:
        mov     eax, 64
        ret

example::lzcnt1:
        jmp     core::core_arch::x86_64::abm::_lzcnt_u64

core::core_arch::x86_64::abm::_lzcnt_u64:
        lzcnt   rax, rdi
        ret

example::lzcnt2:
        lzcnt   rdi, rax
        ret

编译器选项是为了最好地模拟 cargo 的“发布”配置(最好使用 opt-level=3),否则我会尽力让编译器优化功能。具体目标应该没关系,只要是针对x86-64的,我试过x86_64-pc-windows-msvc,gnu,unknown-linux-gnu

预期结果:

所有这些输出都应该与lzcnt2 相同。 Instruction Performance Tables lzcnt 显然是一条快速指令,应该使用,在如此低级的函数中拥有不必要的分支是令人沮丧的。更奇怪的是,函数_lzcnt_u64() 在后台调用leading_zeros() - 编译器很乐意将其魔术掉(也没有检查或断言),但似乎不会为底层函数执行此操作。更重要的是,即使在这种情况下,编译器也不会内联lzcnt 指令? (实现也将函数标记为#[inline])当然,jmp 并没有那么糟糕,但它完全没有必要,应该避免。

可能是什么:

编译器错误? 我不明白的有目的的选择? 我不明白如何正确使用 Compiler Explorer? 其他?

我在 log2 和(我认为)其他函数中看到了类似的结果,这些函数在其实现中依赖于 ctlz rust 编译器。

如果您充分了解编译器,我们将不胜感激。我不喜欢编写大量实用函数,但如果没有更好的选择,我会这样做。

附:如果您的答案是在大多数情况下性能提升可以忽略不计,和/或由于代码质量或类似原因我不应该关心:我理解这种情绪,但这不是这个问题的重点。我正在为个人项目中的裸机热代码编写代码。

【问题讨论】:

【参考方案1】:

旧的 x86-64 CPU 不支持lzcnt,因此默认情况下 rustc/llvm 不会发出它。 (他们会以bsr 执行它,但行为并不相同。)

使用-C target-feature=+lzcnt 启用它。 Try.

更一般地说,您可能希望使用-C target-cpu=XXX 来启用特定 CPU 型号的所有功能。使用rustc --print target-cpus 作为列表。

特别是,-C target-cpu=native 将为运行 rustc 本身的 CPU 生成代码,例如如果您将在编译它的同一台机器上运行代码。

【讨论】:

非常感谢,我会给target-features 看看——正是我需要的。我会尽快接受你的回答。

以上是关于Rust 编译器没有优化 lzcnt? (和类似的功能)的主要内容,如果未能解决你的问题,请参考以下文章

Rust 编译器探索使用 PGO

LLVM编译器优化与应用示例

Zellij-一个典型的 Rust程序的性能优化案例

Zellij-一个典型的 Rust程序的性能优化案例

Zellij-一个典型的 Rust程序的性能优化案例

Zellij-一个典型的 Rust程序的性能优化案例