2012-02-25 122 views
3

我已經減少了我的代碼下到下面,這很簡單,只要我能把它同時保留了編譯器輸出我感興趣。編譯器指令重新排序用C++優化(什麼阻礙他們)

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)... 

是編譯器不這樣做,因爲它只是太難爲它在一般情況下,識別此類優化?還是遵循一些嚴格的規定,禁止它這樣做?如果是這樣,爲什麼,有什麼辦法可以給我一個暗示,這樣做不會改變我的程序的語義?

注:顯然這將是微不足道的只是重新安排代碼,即可獲得最優化的輸出,但我在很感興趣,爲什麼編譯器不會在這樣的情況下優化,不如何在這個這麼做(故意簡化)的情況。

回答

1

有沒有「嚴格規定」控制什麼樣的彙編語言編譯器被允許輸出。如果編譯器可以確定某個代碼塊由於某種先決條件而不需要執行(因爲它沒有副作用),則絕對允許將整個事件短路。

這種類型的優化,可在一般的情況相當複雜,和你的編譯器可能不會去所有的努力。如果這是性能嚴重的代碼,那麼您可以微調源代碼(如您所建議的)以幫助編譯器生成最好的彙編代碼。儘管這是一個反覆試驗的過程,但您可能需要再次爲下一版本的編譯器執行此操作。

+0

我認爲「嚴格規定」不好措辭,我想我真的問的是,因爲它被允許爲所欲爲,只要它能夠確定它是不會改變程序邏輯,有沒有一些具體的事情在這種情況下,防止它假設沒有分配給本地陣列的副作用,哪一個控制路徑剛丟棄而不使用?如果答案僅僅是在一般情況下很困難,那就夠公平的了,這對我來說只是令人驚訝,因爲這似乎是最容易檢測的事情之一。 – kamrann 2012-02-25 09:13:39

+0

我能想到的唯一的事情是編譯器無法知道是否會與其他線程發生可能的交互,尤其是與全局數組。 – 2012-02-25 09:25:16

+0

因此,一個更簡化的案例仍然沒有在任何主要編譯器上得到優化,[根據LLVM傢伙](http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-February/047750 .html)在一般情況下,就像你所說的那樣,這太簡單了。 – kamrann 2012-02-27 23:33:37

3

也許這是爲什麼沒有得到最優化的原因是全球陣列。如果訪問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}; 

第二是相當令人費解,但它可以簡單地是一個錯過的優化(或也許我錯過了別的東西)。

+0

對,我也認爲全球可能是問題所在,但仍然和你一樣,我很驚訝沒有第二種情況的優化,這是我如何定義全局的。實際上VC10仍然複製,然後檢查條件,即使是一個常量全局。無論如何,我進一步簡化爲一個foo()接受3個額外的常量整數參數a,b和c,把它們放到一個大小爲3的局部數組中,完全拋棄全局,然後測試used&a。它在測試條件之前仍然分配了b&c。有任何想法嗎? – kamrann 2012-02-25 09:21:50

+0

更改編譯器。 ;-) – CAFxX 2012-02-25 10:35:29

+0

把笑話放在一邊:http://lists.cs.uiuc.edu/pipermail/llvmdev/2012-February/047746.html – CAFxX 2012-02-25 11:18:50