[英]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 *a
和int *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.这没有利用
a
和b
不能别名的保证。
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 中,
a
和b
仍然有可能别名吗?
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 .这已经发生了多次。
noalias
enabled noalias
noalias
disabled noalias
noalias
enabled noalias
noalias
disabled noalias
noalias
conditionally enabled depending on the version of LLVM the compiler uses noalias
Current case当前案例
Previous case上一案例
Other其他
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.