2017-06-23 161 views
1

我有一些重用代碼,我希望GCC進行積極優化。但我也想用幾個地方調用的(inlinable)函數來編寫乾淨的,可重用的代碼。有些情況下,在內聯函數中,我知道可以刪除的代碼因爲條件永遠不會發生。有沒有辦法告訴GCC參數的範圍?

讓我們看一個具體的例子:

#include <assert.h> 

static inline int foo(int c) 
{ 
    if (c < 4) 
    return c; 
    else 
    return 4; 
} 

int bar(int c) 
{ 
    assert(c < 2); 

    return foo(c); 
} 

隨着-DNDEBUG -O3,GCC仍然會生成(C < 4),即使我知道這比較是沒有必要的,因爲bar功能的前提條件是, c是0或1.沒有-DNDEBUG,GCC 確實刪除比較,因爲它是由斷言暗示 - 但當然你有斷言的開銷(這是更多)。

有沒有辦法將可變範圍傳達給GCC,因此可用於優化?

如果CLANG可以做得更好,我也可以考慮切換編譯器。

+0

Clang 4.0/Zapcc做的比GCC 7.1 - 4的指令略好,而不是x64上的5 - 但它們都不夠聰明,不願選擇foo的c <4。你可以通過https://godbolt.org/g/3Hp4ZA查看各種編譯器,我沒有檢查過它們能夠優化它(這是有道理的)。理想情況下,會有一些神奇的用法指定c的範圍,但我認爲任何人都還沒有想出這樣的pragma ......或者某些聰明的assert內建函數,它可以從生成的代碼中移除它自己,但被優化者認可。 – valiano

+0

@Mike:斷言只是一個例子,我只是刪除第一個,因爲它在這裏不相關(不用於優化)。 – Arnout

+0

@valiano:事實上,我正在尋找一個聰明的斷言。 GIMPLE(海灣合作委員會的內部表示)跟蹤變量範圍,這就是它可以如何優化(c <4)以防止斷言存在。我想要一種方式來明確地表達這樣的範圍,而不是讓編譯器進行分析。 – Arnout

回答

2

您可以在測試中使用__builtin_unreachable(閱讀關於other builtins)以告知編譯器,例如,

if (x<2 || x>100) __builtin_unreachable(); 
// here the compiler knows that x is between 3 and 99 inclusive 

在你的情況加在你bar開始(可能是包裹在一些好看宏):

if (c >= 2) __builtin_unreachable(); 

如果你強烈的優化(如-O2至少)編譯器知道是x介於3和99之間(最近的GCC包含進行這種分析的代碼 - 最少處理簡單的像上面那樣的恆定間隔約束 - 並且在後續的優化過程中利用它們)。

但是,我不太確定你應該使用它! (至少不要經常使用它,並將其包裝在一些類似於assert的宏中),因爲它可能不值得麻煩,並且因爲編譯器實際上只能夠處理和傳播約束(其細節是編譯器版本特定)。 AFAIK最近Clang和GCC都接受了這個內建解決方案。

另請參閱__builtin_trap(它也發出運行時代碼)。

+1

我正準備發佈。你可以把它包裝在宏中:'#define ASSUME(COND)do {if(!(COND))__builtin_unreachable(); } while(0)' – melpomene

+0

工程就像一個魅力!但是,爲什麼你說不使用它? – Arnout

相關問題