Misexpect

當開發人員使用 llvm.expect 內建函數(例如,透過使用 __builtin_expect(...))時,他們試圖將程式碼在執行階段的預期行為傳達給優化器。然而,這些註解可能會因為各種原因而錯誤:程式碼庫的變更會以靜默方式使其失效、開發人員錯誤地註釋(例如,使用 LIKELY 而不是 UNLIKELY),或者他們在編寫註解時可能錯誤地假設了某些事情。無論原因為何,檢測這些情況很有用,以便優化器可以針對程式碼做出更有用的決策。MisExpect 診斷旨在透過將 llvm.expect 內建函數的使用與分析輸入提供的實際情況進行比較,來幫助開發人員識別和解決這些情況。

LLVM 後端中的 MisExpect 檢查遵循一個簡單的程序:如果在分析期間收集的分支權重與 llvm.expect 內建函數提供的權重不匹配,則它會向使用者發出診斷訊息。

執行驗證的最自然位置是在將分支權重以分支權重中繼資料的形式分配給目標指令之前。

LLVM 後端中有 3 個關鍵位置,會根據分析資訊或 llvm.expect 內建函數的使用建立和分配分支權重,而我們的實作重點關注這些位置以執行驗證。

我們根據編譯器分配給 llvm.expect 內建函數的值計算發出 MisExpect 相關診斷的閾值,這些值可以透過 -likely-branch-weight-unlikely-branch-weight LLVM 選項進行設定。在驗證期間,如果分析權重與計算的閾值不匹配,則我們將發出備註或警告,詳細說明潛在的效能回歸。診斷還會報告分析期間註解正確的時間百分比,以幫助開發人員推斷如何繼續。

診斷還可以最佳化備註的形式提供,這些備註可以透過 LLVM 中的 opt-viewer.py 腳本進行序列化和處理。

-pass-remarks=misexpect

當分析資料與 llvm.expect 內建函數的使用衝突時,啟用 misexpect 的最佳化備註。

-pgo-warn-misexpect

當分析資料與 llvm.expect 內建函數的使用衝突時,啟用 misexpect 警告。

LLVM 支援 4 種設定檔格式:Frontend、IR、CS-IR 和 Sampling。MisExpect Diagnostics 與所有設定檔格式相容。

設定檔類型

說明

Frontend

由前端(例如 clang)在編譯期間添加的設定檔檢測

IR

由 LLVM 後端添加的設定檔檢測

CS-IR

基於上下文敏感 IR 的設定檔

Sampling

透過外部工具(例如 Linux 上的 perf)進行採樣收集的設定檔