簡體   English   中英

編譯器指令重新排序C ++中的優化(以及禁止它們的原因)

[英]Compiler instruction reordering optimizations in C++ (and what inhibits them)

我已經將代碼縮減到以下內容,這是我可以做到的一樣簡單,同時保留了我感興趣的編譯器輸出。

void foo(const uint64_t used)
{
    uint64_t ar[100];
    for(int i = 0; i < 100; ++i)
    {
        ar[i] = some_global_array[i];
    }

    const uint64_t mask = ar[0];
    if((used & mask) != 0)
    {
        return;
    }

    bar(ar); // Not inlined
}

將VC10與/ O2和/ Ob1一起使用,生成的程序集幾乎反映了上述C ++代碼中的指令順序。 由於本地數組ar僅在條件失敗時傳遞給bar() ,否則未使用,我原本期望編譯器優化到類似下面的內容。

if((used & some_global_array[0]) != 0)
{
    return;
}

// Now do the copying to ar and call bar(ar)...

編譯器是不是這樣做,因為在一般情況下它很難識別出這樣的優化嗎? 或者是否遵循一些禁止它這樣做的嚴格規定? 如果是這樣,為什么,並且有什么方法可以給它一個暗示,這樣做不會改變我的程序的語義?

注意:顯然通過重新排列代碼來獲得優化輸出是微不足道的,但我感興趣的是為什么編譯器在這種情況下不會優化,而不是在這種(故意簡化的)情況下如何這樣做。

可能之所以沒有得到優化的原因是全局陣列。 編譯器無法事先知道,例如,訪問some_global_array[99]會導致生成某種異常/信號,因此必須執行整個循環。 如果全局數組在同一個編譯單元中靜態定義,情況就會大不相同。

例如,在LLVM中,全局數組的以下三個定義將產生該函數的截然不同的輸出:

// this yields pretty much what you're seeing
uint64_t *some_global_array; 
// this calls memcpy and then performs the conditional check
uint64_t some_global_array[100] = {0};
// this calls memset (not memcpy!) on the ar array and then bar directly (no 
// conditional checks since the array is const and filled with 0s, so the if
// is always false) 
const uint64_t some_global_array[100] = {0};

第二個是非常令人費解的,但它可能只是一個錯過的優化(或者我可能缺少其他東西)。

沒有“嚴格的規則”來控制允許編譯器輸出什么樣的匯編語言。 如果編譯器可以確定由於某些先決條件而不需要執行代碼塊(因為它沒有副作用),那么絕對允許將整個事件短路。

在一般情況下,這種優化可能相當復雜,並且您的編譯器可能不會全力以赴。 如果這是性能關鍵代碼,那么您可以微調源代碼(如您所建議的那樣)以幫助編譯器生成最佳匯編代碼。 這是一個試錯過程,您可能必須再次為下一版本的編譯器執行此操作。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM