[英]How the GNU builtin function `__builtin_unreachable ` works in this code snippet?
我的項目中有一個代碼片段,其中使用了__builtin_unreachable
函數,但我不知道為什么需要它。
我從GNU __builtin_unreachable中讀到,似乎__builtin_unreachable
函數用於通知編譯器在CPU運行時期間永遠不會到達此行,因此可以提前阻止編譯中的大量抱怨。 但是我不明白為什么在這段代碼片段中需要這個功能,似乎沒有任何事情會通過刪除__builtin_unreachable
。
# define ATHCONTAINERS_ASSUME(x) do { if (!(x)) __builtin_unreachable(); } while(0)
inline
void*
AuxVectorData::Cache::getDataArray (SG::auxid_t auxid,
AuxVectorData& parent)
{
// This function is important for performance.
// Be careful when changing it.
void* ptr = cachePtr (auxid);
if (ATHCONTAINERS_UNLIKELY (ptr == 0)) {
// We don't have the variable cached.
// Call the out-of-line routine to get it cached.
ptr = parent.getDataOol (auxid, false);
// These inform the compiler of what the previous call did.
// They tell the optimizer that it can now assume that this cache
// entry is valid.
ATHCONTAINERS_ASSUME (ptr != 0);
ATHCONTAINERS_ASSUME (cachePtr (auxid) != 0);
ATHCONTAINERS_ASSUME (cachePtr (auxid) == ptr);
}
return ptr;
}
ATHCONTAINERS_ASSUME
告訴編譯器它的參數x
不能為false。 這使編譯器不必生成任何代碼以適應x
為假的可能性。 例如,當編譯器看到ATHCONTAINERS_ASSUME (ptr != 0)
它可以假設ptr
不為空,並且任何與該假設相矛盾的代碼都可以被優化掉,因為它將是未定義的行為。
例如,由於getDataArray()
是inline
,編譯器可以在每個調用站點知道返回的指針永遠不會為null。 所以如果調用者這樣做:
if (void* p = cache.getDataArray(aux, parent))
memcpy(p, "OK", 2);
編譯器可以生成直接寫入“OK”而不執行空檢查的代碼。
這很有趣,對我來說很新。
我最好的理解,從您鏈接到的文檔說:
如果控制流到達
__builtin_unreachable()
的點,則程序未定義。
因此,如果條件為false,宏基本上會達到未定義的行為。 因此,假設編譯器能夠基於不發生的假設進行優化,即條件不是假的。
我有興趣比較使用和不使用這些宏來構建代碼的結果,以進一步了解它所產生的實際差異。
依靠這個來實現某種優化對我來說似乎有些“脆弱”,因為它假定了很多關於編譯器的內部功能。
正如代碼注釋所示,它向優化器講述故事。
這告訴我的第一件事是編譯器可以假設返回值不是空指針。 如果將使用另一個gcc擴展名,即__attribute__((__returns_nonnull__))
,它可能會提高代碼的可讀性。 將此添加到getDataArray
的接口也可以保證該屬性,即使編譯器決定不能出於任何原因內聯它。
但它告訴的不止於此。 它還告訴(或試圖告訴)將來使用相同參數調用cachePtr
將返回相同的結果。
通過刪除未使用的parent
參數(以避免別名分析)以及將__attribute__((__const__))
到getDataArray
可以更好地保證所有這些屬性。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.