![](/img/trans.png)
[英]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?
[英]Why does the Rust compiler not optimize code assuming that two mutable references cannot alias?
據我所知,引用/指針別名會阻礙編譯器生成優化代碼的能力,因為它們必須確保生成的二進制文件在兩個引用/指針確實別名的情況下正確運行。 例如,在下面的 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
這里代碼存儲回(%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
和-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 中使用&mut
那樣頻繁地使用restrict
。
這已經發生了多次。
noalias
noalias
noalias
noalias
noalias
當前案例
上一案例
其他
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.