標籤:

編譯時能否關閉clang的所有優化?我試過-O0,但是編譯成彙編之後還是自動進行了一些優化?


不能,即使在O0的情況下,Clang依然會有邏輯做一些優化,比如if條件的常量摺疊,如下面的例子:

int main() {
const int i = 7;
if (i) {
return 1;
}
return 0;
}

在O0的情況下,Clang會直接消除掉這個if判斷,直接生成return 1。

如果是一個變數,如變為int i = 7;那麼就會有跳轉指令的生成。

這在Clang的代碼中,叫做常量摺疊。在代碼生成的時候就做了:

核心方法是ConstantFoldsToSimpleInteger,如果Clang能算出來這裡的If條件,就會直接消除這裡的If條件。所以,你O0的時候不能關閉所有的優化,除非你自己處理Clang的邏輯,然後編譯出來自己的Clang(我就經常這樣做)。

說到這裡的消除If常量,目前Clang官方是有"Bug"的,它的代碼實現沒有達到它想要的目的。舉個例子:

int main() {
int i = 7;
if (i || 1) {
return 1;
}
return 0;
}

在這段代碼中, i 並不是一個函數調用,沒有side effect. 但是這個 i || 1恆定為真,所以正常來說,應該消除if。但是官方的Clang並沒有:

依然生成了br指令。但是GCC是做到了的。

可以看到GCC是直接跳到第4行,而非if條件的地方。然而Clang因為生成了br指令,會執行if.

我已經修復了Clang的這個Bug,目前還沒有回饋交到開源社區。


自己改llvm的pass manager 關掉所有優化pass

不過我也沒試過 不確定關掉所有優化pass是否還能正確編譯

雖然理論上應該可行 還是得看實現 畢竟llvm內部不少pass對之前的分析或者優化是存在一定的假定的


你倒是貼代碼啊QAQ


我不知道什麼算「優化」,但是我遇到了不講道理。。

https://github.com/yuanzhubi/call_in_stack/blob/master/call_in_stack_x64_sysv.h#L197

這裡有一行代碼,x64下如果用O0 編譯,無論如何設置破壞性描述符,clang 都會去破壞rax或者rdx寄存器,十分讓我無解。哪怕是最新的clang版本都這樣。

可以試著編譯test.cpp之後 gdb disassmble call_in_stack_impl::do_call&(unsigned long, unsigned long, unsigned long, int, void*, char*)

注意看到那2段代碼很無語的強行破壞rax寄存器。。

(注意這個庫用clang3.9之前的版本編譯測試用例都會有問題,因為各種奇怪的clang bug甚至罷工。gcc沒有問題。)

附錄:代碼解釋(這段代碼專門給O0準備的,因為x64 gcc也不支持naked)

再來一個小例子

#include &
const char* out = "Hello world!";
int test0(const char* di, typeof(puts) p, int dx,int cx,int r8,int r9){
__asm__ __volatile__ ("":::"rax","rdi","rsi","rdx","rcx","r8","r9");
__asm__ __volatile__("call *%0;
" ::"X"(p):"rax","rdi","rsi","rdx","rcx","r8","r9");
return 0;
}

int test1(const char* di, typeof(puts) p, int dx,int cx,int r8,int r9){
__asm__ __volatile__("call *%0;
" ::"X"(p):"rax","rdi","rsi","rdx","rcx","r8","r9");
return 0;
}

int test2(const char* di, typeof(puts) p, int dx,int cx,int r8,int r9){
__asm__ __volatile__ ("":::"rax","rdi","rsi","rdx","rcx","r8","r9");
__asm__ __volatile__("call *%0;
" ::"X"(p));
return 0;
}

int test3(const char* di, typeof(puts) p, int dx,int cx,int r8,int r9){
__asm__ __volatile__("call *%0;
" ::"X"(p));
return 0;
}

int main(){
test0(out, puts,1,2,3,4);
test1(out, puts,1,2,3,4);
test2(out, puts,1,2,3,4);
test3(out, puts,1,2,3,4);
return 0;
}

clang O0編譯的結果:4個函數分別侵犯rax, rsi, rax, rsi. @藍色 gcc則沒這個問題。


emmmmmm我也遇到了這個問題,不知道題主解決了沒有,我來貼個例子吧,這是源碼

接著用clang編譯

clang -O0 -S test.c

下面是編譯結果

再用gcc編譯(結果太長。。。就截取了前面一段)

gcc-6 -O0 -S test.c

都是沒開優化選項的,但是clang對於我沒有使用的static數組竟然沒有分配空間,這就很奇怪了。。。(知乎為什麼沒有像stackoverflow那樣的補充問題的位置啊啊啊啊)


有的在你看來的優化其實不是優化,而是本來的編譯流程


用的是debug模式嗎?


推薦閱讀:

是否可以將不同語言編譯到LLVM IR層面鏈接?如果可以,與傳統的編譯為目標代碼鏈接有什麼不同?
libgccjit和LLVM相比,有哪些優點?
LLVM相比於JVM,有哪些技術優勢?
過程間和過程內的數據流分析演算法在類似LLVM的IR或HotSpot C1的HIR中,是如何實現的?

TAG:LLVM |