如何提交 LLVM 錯誤報告¶
簡介 - 遇到錯誤了嗎?¶
如果您在使用 LLVM 時遇到錯誤,我們絕對希望知道。本文檔描述了您可以做些什麼來提高錯誤快速修復的機率。
🔒 如果您認為錯誤與安全性相關,請遵循如何報告安全性問題?。 🔒
基本上,您至少需要做兩件事。首先,判斷錯誤是導致編譯器崩潰,還是編譯器錯誤編譯程式(即,編譯器成功產生可執行檔,但執行不正確)。根據錯誤類型,請按照連結章節中的說明縮小錯誤範圍,以便修復錯誤的人員更容易找到問題。
一旦您有了縮減後的測試案例,請前往LLVM 錯誤追蹤系統並填寫包含必要詳細資訊的表單(請注意,您不需要選擇標籤,如果您不確定就使用即可)。錯誤描述應包含以下資訊
重現問題所需的所有資訊。
觸發錯誤的縮減後的測試案例。
您取得 LLVM 的位置(如果不是從我們的 Git 儲存庫)。
感謝您協助我們讓 LLVM 變得更好!
崩潰錯誤¶
通常,編譯器中的錯誤會導致其崩潰——通常是由於某種斷言失敗。最重要的環節是弄清楚崩潰是發生在 Clang 前端,還是 LLVM 程式庫之一(例如,最佳化器或程式碼產生器)出現問題。
為了弄清楚哪個組件崩潰(前端、中端最佳化器或後端程式碼產生器),請以崩潰發生時的方式執行 clang
命令列,但使用以下額外的命令列選項
-emit-llvm -Xclang -disable-llvm-passes
:如果clang
在傳遞這些選項(禁用最佳化器和程式碼產生器)時仍然崩潰,則崩潰發生在前端。跳至前端錯誤。-emit-llvm
:如果clang
在使用此選項(禁用程式碼產生器)時崩潰,則您發現了中端最佳化器錯誤。跳至中端錯誤。否則,您遇到了後端程式碼產生器崩潰。跳至程式碼產生器錯誤。
前端錯誤¶
在 clang
崩潰時,編譯器將傾印預處理檔案和一個用於重播 clang
命令的腳本。例如,您應該看到類似以下內容
PLEASE ATTACH THE FOLLOWING FILES TO THE BUG REPORT:
Preprocessed source(s) and associated run script(s) are located at:
clang: note: diagnostic msg: /tmp/foo-xxxxxx.c
clang: note: diagnostic msg: /tmp/foo-xxxxxx.sh
creduce 工具可協助將預處理檔案縮減為仍然重現問題的最小程式碼量。我們鼓勵您使用 creduce 來縮減程式碼,以減輕開發人員的工作負擔。clang/utils/creduce-clang-crash.py
腳本可用於 clang 傾印的檔案,以協助自動建立測試以檢查編譯器崩潰。
cvise 是 creduce
的替代方案。
中端最佳化錯誤¶
如果您發現錯誤在最佳化器中崩潰,請將您的測試案例編譯為 .bc
檔案,方法是傳遞 “-emit-llvm -O1 -Xclang -disable-llvm-passes -c -o foo.bc
”。-O1
很重要,因為 -O0
會將 optnone
函數屬性新增至所有函數,而且許多 pass 不會在 optnone
函數上執行。然後執行
opt -O3 foo.bc -disable-output
如果這沒有崩潰,請按照前端錯誤的說明進行操作。
如果這確實崩潰,那麼您應該能夠使用以下bugpoint 命令進行偵錯
bugpoint foo.bc -O3
執行此命令,然後提交包含 bugpoint 發出的說明和縮減後的 .bc 檔案的錯誤報告。
如果 bugpoint 無法重現崩潰,llvm-reduce
是縮減 LLVM IR 的替代方法。建立一個重現崩潰的腳本並執行
llvm-reduce --test=path/to/script foo.bc
這應該會產生重現崩潰的縮減後的 IR。請注意,llvm-reduce
仍然相當不成熟,可能會崩潰。
如果以上方法都不起作用,您可以透過執行 opt
命令並使用 --print-before-all --print-module-scope
標誌來傾印每個 pass 之前的 IR,以取得崩潰之前的 IR。請注意,這非常冗長。
後端程式碼產生器錯誤¶
如果您發現一個錯誤導致 clang 在程式碼產生器中崩潰,請將您的原始碼檔案編譯為 .bc 檔案,方法是將 “-emit-llvm -c -o foo.bc
” 傳遞給 clang(除了您已經傳遞的選項之外)。一旦您有了 foo.bc,以下命令之一應該會失敗
llc foo.bc
llc foo.bc -relocation-model=pic
llc foo.bc -relocation-model=static
如果這些都沒有崩潰,請按照前端錯誤的說明進行操作。如果其中一個崩潰,您應該能夠使用以下bugpoint 命令列之一來縮減此錯誤(使用與上面失敗的命令相對應的命令)
bugpoint -run-llc foo.bc
bugpoint -run-llc foo.bc --tool-args -relocation-model=pic
bugpoint -run-llc foo.bc --tool-args -relocation-model=static
請執行此命令,然後提交包含 bugpoint 發出的說明和縮減後的 .bc 檔案的錯誤報告。如果 bugpoint 出現問題,請提交 “foo.bc” 檔案以及導致 llc 崩潰的選項。
LTO 錯誤¶
如果您在使用 -flto
選項時遇到導致 LLVM LTO 階段崩潰的錯誤,請按照以下步驟診斷和報告問題
除了您現有的編譯選項之外,還可以使用以下選項將您的原始碼檔案編譯為 .bc
(位元碼) 檔案
export CFLAGS="-flto -fuse-ld=lld" CXXFLAGS="-flto -fuse-ld=lld" LDFLAGS="-Wl,-plugin-opt=save-temps"
這些選項啟用 LTO 並儲存編譯期間產生的臨時檔案,以供日後分析。
在 Windows 上,您應該使用 lld-link 作為連結器。調整您的編譯標誌如下:* 將 /lldsavetemps
新增至連結器標誌。* 從編譯器驅動程式連結時,新增 /link /lldsavetemps
以便將該標誌轉發到連結器。
使用指定的標誌將產生四個中繼位元組碼檔案
a.out.0.0.preopt.bc (在套用任何連結時間最佳化 (LTO) 之前)
a.out.0.2.internalize.bc (在套用初始最佳化之後)
a.out.0.4.opt.bc (在經過大量最佳化之後)
a.out.0.5.precodegen.bc (在 LTO 之後但在轉換為機器碼之前)
執行以下命令之一以識別問題來源
opt "-passes=lto<O3>" a.out.0.2.internalize.bc
llc a.out.0.5.precodegen.bc
如果其中一個崩潰,您應該能夠使用llvm-reduce 命令列來縮減此錯誤(使用與上面失敗的命令相對應的 bc 檔案)
llvm-reduce --test reduce.sh a.out.0.2.internalize.bc
reduce.sh 腳本範例
$ cat reduce.sh
#!/bin/bash -e
path/to/not --crash path/to/opt "-passes=lto<O3>" $1 -o temp.bc 2> err.log
grep -q "It->second == &Insn" err.log
在這裡,我們已經 grepped 失敗的斷言訊息。
請執行此命令,然後提交包含 llvm-reduce 發出的說明和縮減後的 .bc 檔案的錯誤報告。
錯誤編譯¶
如果 clang 成功產生可執行檔,但該可執行檔執行不正確,則可能是程式碼中的錯誤或編譯器中的錯誤。首先要檢查的是確保它沒有使用未定義的行為(例如,在變數定義之前讀取變數)。特別是,檢查程式在各種sanitizers(例如,clang -fsanitize=undefined,address
)和valgrind下是否乾淨。我們追蹤到的許多 “LLVM 錯誤” 最終都是被編譯的程式中的錯誤,而不是 LLVM。
一旦您確定程式本身沒有錯誤,您應該選擇要使用哪個程式碼產生器來編譯程式(例如,LLC 或 JIT),並可選擇一系列要運行的 LLVM pass。例如
bugpoint -run-llc [... optzn passes ...] file-to-test.bc --args -- [program arguments]
bugpoint 將嘗試縮小您的 pass 列表,找到導致錯誤的 pass,並盡可能簡化位元碼檔案以協助您。它將列印一則訊息,告知您如何重現產生的錯誤。
OptBisect 頁面顯示了一種尋找不正確最佳化 pass 的替代方法。
不正確的程式碼產生¶
與偵錯 pass 行為不當導致的不正確編譯類似,您可以透過 LLC 或 JIT 偵錯不正確的程式碼產生,方法是使用 bugpoint
。在這種情況下,bugpoint
遵循的流程是嘗試將程式碼縮小到一個被其中一種方法錯誤編譯的函數,但由於為了正確性,必須執行整個程式,bugpoint
將使用 C 後端編譯它認為不受影響的程式碼,然後連結到它產生的共享物件。
要偵錯 JIT
bugpoint -run-jit -output=[correct output file] [bitcode file] \
--tool-args -- [arguments to pass to lli] \
--args -- [program arguments]
同樣,要偵錯 LLC,可以運行
bugpoint -run-llc -output=[correct output file] [bitcode file] \
--tool-args -- [arguments to pass to llc] \
--args -- [program arguments]
特別注意:如果您要偵錯已經存在於 llvm/test
層次結構中的 MultiSource 或 SPEC 測試,則有一種更簡單的方法可以使用預先編寫的 Makefile 目標來偵錯 JIT、LLC 和 CBE,這將傳遞 Makefile 中指定的程式選項
cd llvm/test/../../program
make bugpoint-jit
在成功執行 bugpoint
結束時,您將看到兩個位元碼檔案:一個 safe 檔案,可以使用 C 後端編譯,以及一個 test 檔案,LLC 或 JIT 會錯誤地產生程式碼,從而導致錯誤。
要重現 bugpoint
發現的錯誤,只需執行以下操作
從 safe 位元碼檔案重新產生共享物件
llc -march=c safe.bc -o safe.c gcc -shared safe.c -o safe.so
如果偵錯 LLC,請編譯 test 位元碼原生碼並與共享物件連結
llc test.bc -o test.s gcc test.s safe.so -o test.llc ./test.llc [program options]
如果偵錯 JIT,請載入共享物件並提供 test 位元碼
lli -load=safe.so test.bc [program options]