簡體   English   中英

為什么 Rust 編譯器不優化代碼,假設兩個可變引用不能別名?

[英]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 *aint *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

這沒有利用ab不能別名的保證。

這是因為當前的 Rust 編譯器仍在開發中,還沒有結合別名分析來進行優化嗎?

這是因為即使在安全的 Rust 中, ab仍然有可能別名嗎?

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

這已經發生了多次

  • 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 通過 ??? — 根據編譯器使用的 LLVM 版本有條件地啟用noalias

相關 Rust 問題

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM