Zhi*_* Ma 268 compiler-optimization rust llvm-codegen
据我所知,引用/指针别名会阻碍编译器生成优化代码的能力,因为它们必须确保在两个引用/指针确实是别名的情况下,生成的二进制文件的行为正确。例如,在以下C代码中,
void adds(int *a, int *b) {
*a += *b;
*a += *b;
}
Run Code Online (Sandbox Code Playgroud)
当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
Run Code Online (Sandbox Code Playgroud)
下面的代码存回(%rdi)
两次的情况下,int *a
和int *b
别名。
当我们明确告诉编译器这两个指针不能使用restrict
关键字别名时:
void adds(int * restrict a, int * restrict b) {
*a += *b;
*a += *b;
}
Run Code Online (Sandbox Code Playgroud)
然后Clang将发出二进制代码的更优化版本:
0000000000000000 <adds>:
0: 8b 06 mov (%rsi),%eax
2: 01 c0 add %eax,%eax
4: 01 07 add %eax,(%rdi)
6: c3 retq
Run Code Online (Sandbox Code Playgroud)
由于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;
}
Run Code Online (Sandbox Code Playgroud)
它产生:
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
Run Code Online (Sandbox Code Playgroud)
这不采取保证的优势a
,并b
不能别名。
这是因为当前的Rust编译器仍在开发中,并且尚未合并别名分析来进行优化吗?
这是因为即使在安全的Rust中,仍然有可能a
并b
可能出现别名吗?
She*_*ter 323
Rust最初确实启用了LLVM的noalias
属性,但这导致了错误编译的代码。当所有受支持的LLVM版本不再重新编译代码时,它将重新启用。
如果添加-Zmutable-noalias=yes
到编译器选项,则会得到预期的程序集:
adds:
mov eax, dword ptr [rsi]
add eax, eax
add dword ptr [rdi], eax
ret
Run Code Online (Sandbox Code Playgroud)
简而言之,Rust将C的restrict
关键字等价于各处,比任何普通的C程序都要普遍得多。这对LLVM的极端情况产生了超出其正确处理能力的影响。事实证明,C和C ++程序员根本不像Rust中restrict
那样频繁&mut
使用。
这已经发生过多次了。
noalias
启用noalias
禁用noalias
启用noalias
禁用当前案例
前案
其他
归档时间: |
|
查看次数: |
33137 次 |
最近记录: |