据我所知,引用/指针别名可能会妨碍编译器生成优化代码的能力,因为它们必须确保生成的二进制文件在两个引用/指针确实别名的情况下正确运行.例如,在下面的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
在这里,代码在情况int *a
和int *b
中两次存储回(%rdi)
.
当我们明确告诉编译器这两个指针不能与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
这并没有利用a
和b
不能使用别名的保证.
这是因为当前的Rust编译器仍在开发中,还没有结合别名分析来进行优化吗?
这是不是因为a
和b
仍然有可能被替代,即使是在安全的情况下?