rust - 假设两个可变引用不能别名,为什么 Rust 编译器不优化代码?
问题描述
据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保生成的二进制文件在两个引用/指针确实别名的情况下正确运行。例如,在下面的 C 代码中,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
当clang version 6.0.0-1ubuntu2 (tags/RELEASE_600/final)
使用-O3
标志编译时,它会发出
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 *a
和int *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
当我使用下面的代码进行测试并使用with 进行编译时-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
这没有利用保证a
并且b
不能别名。
这是因为当前的 Rust 编译器仍在开发中,还没有结合别名分析来进行优化吗?
这是因为即使在安全的 Rust 中,仍然有可能a
并且可以别名?b
解决方案
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 中restrict
那样频繁使用。&mut
这已经发生过多次了。
- 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 到 ??? —
noalias
根据编译器使用的 LLVM 版本有条件地启用
相关的 Rust 问题
当前案例
上一个案例
其他
推荐阅读
- android - 将 json 传递给包含 json 数组的服务器
- javascript - 使用 .addClass 函数时,边框不会在单击时显示
- firebase - Flutter - 收到firebase通知后重定向
- java - 无法使用 MailService 从 com.google.appengine 库进行 API 调用 mail.Send
- javascript - 如何在后台运行谷歌街景时弹出模式
- powershell - Powershell脚本不适用于附件
- javascript - 我的 Javascript 函数没有设置日期
- rx-java - 初始化后如何更改 rxjava/rxscala 运算符(.debounce)参数
- excel - 有没有更好的方法来搜索一列并将偏移量复制到另一张纸上?
- javascript - 如何在 pupeteer 中模拟拖放动作