繁体   English   中英

为什么 Rust 编译器不优化代码,假设两个可变引用不能别名?

[英]Why does the Rust compiler not optimize code assuming that two mutable references cannot alias?

据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保生成的二进制文件在两个引用/指针确实别名的情况下正确运行。 例如,在下面的 C 代码中,

void adds(int  *a, int *b) {
    *a += *b;
    *a += *b;
}

当使用-O3标志由clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)编译时,它发出

0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)  # The first time
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)  # The second time
   a:    c3                       retq

这里代码存储回(%rdi)两次,以防int *aint *b别名。

当我们明确告诉编译器这两个指针不能用restrict关键字做别名时:

void adds(int * restrict a, int * restrict b) {
    *a += *b;
    *a += *b;
}

然后 Clang 将发出二进制代码的更优化版本:

0000000000000000 <adds>:
   0:    8b 06                    mov    (%rsi),%eax
   2:    01 c0                    add    %eax,%eax
   4:    01 07                    add    %eax,(%rdi)
   6:    c3                       retq

由于 Rust 确保(除了在不安全代码中)两个可变引用不能别名,我认为编译器应该能够发出更优化的代码版本。

当我使用下面的代码进行测试并使用rustc 1.35.0-C opt-level=3 --emit obj编译它时,

#![crate_type = "staticlib"]
#[no_mangle]
fn adds(a: &mut i32, b: &mut i32) {
    *a += *b;
    *a += *b;
}

它产生:

0000000000000000 <adds>:
   0:    8b 07                    mov    (%rdi),%eax
   2:    03 06                    add    (%rsi),%eax
   4:    89 07                    mov    %eax,(%rdi)
   6:    03 06                    add    (%rsi),%eax
   8:    89 07                    mov    %eax,(%rdi)
   a:    c3                       retq

这没有利用ab不能别名的保证。

这是因为当前的 Rust 编译器仍在开发中,还没有结合别名分析来进行优化吗?

这是因为即使在安全的 Rust 中, ab仍然有可能别名吗?

Rust 最初确实启用了 LLVM 的noalias属性,但这会导致错误编译的代码 当所有支持的 LLVM 版本不再错误编译代码时,它将重新启用

如果将-Zmutable-noalias=yes添加到编译器选项,您将获得预期的程序集:

adds:
        mov     eax, dword ptr [rsi]
        add     eax, eax
        add     dword ptr [rdi], eax
        ret

简而言之,Rust 在任何地方都放置了相当于 C 的restrict关键字,比任何普通的 C 程序都流行得多。 这对 LLVM 的极端情况进行了超出其正确处理的能力。 事实证明,C 和 C++ 程序员根本不会像 Rust 中使用&mut那样频繁地使用restrict

这已经发生了多次

  • Rust 1.0 到 1.7 — 启用noalias
  • Rust 1.8 到 1.27 — 禁用noalias
  • Rust 1.28 到 1.29 — 启用noalias
  • Rust 1.30 到 1.54 — 禁用noalias
  • Rust 1.54 通过 ??? — 根据编译器使用的 LLVM 版本有条件地启用noalias

相关 Rust 问题

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM