简体   繁体   English

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

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

As far as I know, reference/pointer aliasing can hinder the compiler's ability to generate optimized code, since they must ensure the generated binary behaves correctly in the case where the two references/pointers indeed alias.据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保生成的二进制文件在两个引用/指针确实别名的情况下正确运行。 For instance, in the following C code,例如,在下面的 C 代码中,

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

when compiled by clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final) with the -O3 flag, it emits当使用-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

Here the code stores back to (%rdi) twice in case int *a and int *b alias.这里代码存储回(%rdi)两次,以防int *aint *b别名。

When we explicitly tell the compiler that these two pointers cannot alias with the restrict keyword:当我们明确告诉编译器这两个指针不能用restrict关键字做别名时:

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

Then Clang will emit a more optimized version of the binary code:然后 Clang 将发出二进制代码的更优化版本:

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

Since Rust makes sure (except in unsafe code) that two mutable references cannot alias, I would think that the compiler should be able to emit the more optimized version of the code.由于 Rust 确保(除了在不安全代码中)两个可变引用不能别名,我认为编译器应该能够发出更优化的代码版本。

When I test with the code below and compile it with rustc 1.35.0 with -C opt-level=3 --emit obj ,当我使用下面的代码进行测试并使用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;
}

it generates:它产生:

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

This does not take advantage of the guarantee that a and b cannot alias.这没有利用ab不能别名的保证。

Is this because the current Rust compiler is still in development and has not yet incorporated alias analysis to do the optimization?这是因为当前的 Rust 编译器仍在开发中,还没有结合别名分析来进行优化吗?

Is this because there is still a chance that a and b could alias, even in safe Rust?这是因为即使在安全的 Rust 中, ab仍然有可能别名吗?

Rust originally did enable LLVM's noalias attribute, but this caused miscompiled code . Rust 最初确实启用了 LLVM 的noalias属性,但这会导致错误编译的代码 When all supported LLVM versions no longer miscompile the code, it will be re-enabled .当所有支持的 LLVM 版本不再错误编译代码时,它将重新启用

If you add -Zmutable-noalias=yes to the compiler options, you get the expected assembly:如果将-Zmutable-noalias=yes添加到编译器选项,您将获得预期的程序集:

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

Simply put, Rust put the equivalent of C's restrict keyword everywhere , far more prevalent than any usual C program.简而言之,Rust 在任何地方都放置了相当于 C 的restrict关键字,比任何普通的 C 程序都流行得多。 This exercised corner cases of LLVM more than it was able to handle correctly.这对 LLVM 的极端情况进行了超出其正确处理的能力。 It turns out that C and C++ programmers simply don't use restrict as frequently as &mut is used in Rust.事实证明,C 和 C++ 程序员根本不会像 Rust 中使用&mut那样频繁地使用restrict

This has happened multiple times .这已经发生了多次

  • Rust 1.0 through 1.7 — noalias enabled Rust 1.0 到 1.7 — 启用noalias
  • Rust 1.8 through 1.27 — noalias disabled Rust 1.8 到 1.27 — 禁用noalias
  • Rust 1.28 through 1.29 — noalias enabled Rust 1.28 到 1.29 — 启用noalias
  • Rust 1.30 through 1.54 — noalias disabled Rust 1.30 到 1.54 — 禁用noalias
  • Rust 1.54 through ??? Rust 1.54 通过 ??? noalias conditionally enabled depending on the version of LLVM the compiler uses — 根据编译器使用的 LLVM 版本有条件地启用noalias

Related Rust issues相关 Rust 问题

暂无
暂无

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

相关问题 为什么在将变量移动到 scope 后 Rust 编译器错误“不能作为不可变借用,因为它也作为可变借用”? - Why does the Rust compiler error with "cannot borrow as immutable because it is also borrowed as mutable" after moving the variable into a scope? 为什么 Rust 会阻止多个可变引用? - Why Rust prevents from multiple mutable references? 为什么 Rust 编译器在它应该是不可变的地方接受可变值? - Why does the Rust compiler accept a mutable value where it should've been immutable? 假设指向同一变量的两个指针是非法的/UB,为什么 C 编译器不能优化更改 const 指针的值? - Why can't the C compiler optimize changing the value of a const pointer assuming that two pointers to the same variable would be illegal/UB? 在 Rust 中一次从全局哈希映射访问两个可变引用 - Access two mutable references from a Global hashmap at once in Rust 在 Rust 中创建两个对结构是线程安全的可变引用 - Create two mutable references that are thread safe to a struct in Rust 为什么 Rust 不允许可变别名? - Why does Rust disallow mutable aliasing? Rust - 不能作为可变借用 - Rust - cannot borrow as mutable Rust 编译器不期望可变引用,而应该期望可变引用 - Rust compiler does not expect a mutable reference where a mutable reference should be expected 为什么Rust编译器不能优化Box :: downcast的Err arm? - Why can the Rust compiler not optimize away the Err arm of Box::downcast?
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM