2012-03-20 36 views
0

所以,我正在製作一個Hack CPU模擬器,我想知道計算輸出的最好方法是什麼。將輸出計算結果集中到一個不可讀的行中會比一次一步計算結果更有效嗎?編譯器是否對它進行了優化,使得這兩個選項都很好?基本上,它的這些是更有效 -計算邏輯方程的最佳選擇?

這樣的:

 
    word HackALU(word x, word y, bool zx, bool nx, bool zy, bool ny, bool f, bool no) 
    { 
     x = zx ? 0 : x; 
     y = zy ? 0 : y; 

     x = nx ? ~x : x; 
     y = ny ? ~y : y; 

     word result = f ? x + y : x & y; 

     return no ? ~result : result;  
    } 

或本:

 
    word HackALU(word x, word y, bool zx, bool nx, bool zy, bool ny, bool f, bool no) 
    { 
     return no ? ~(f ? ((nx ? ~(zx ? 0 : x) : (zx ? 0 : x)) + (ny ? ~(zy ? 0 : y) : (zy ? 0 : y))) : ((nx ? ~(zx ? 0 : x) : (zx ? 0 : x)) & (ny ? ~(zy ? 0 : y) : (zy ? 0 : y)))) : (f ? ((nx ? ~(zx ? 0 : x) : (zx ? 0 : x)) + (ny ? ~(zy ? 0 : y) : (zy ? 0 : y))) : ((nx ? ~(zx ? 0 : x) : (zx ? 0 : x)) & (ny ? ~(zy ? 0 : y) : (zy ? 0 : y)))); 
    } 
+0

這些似乎並沒有更換分支是相同的代碼。例如,nx在上面的例子中根本不使用,但似乎影響下面的代碼塊的結果。 – 2012-03-20 19:51:24

+0

我犯了一個錯字。它現在已經修復,所以它們應該產生相同的結果。 – Avi 2012-03-21 03:16:06

回答

1

良好的現代編譯器將最有可能產生兩個相同的代碼。

+0

這很好。因爲第一個實際使用更多的內存,因此它將單詞'result'保存到內存中。編譯器會消除這一步? – Avi 2012-03-21 03:16:38

+1

如果我在x86上使用gcc 3.3.4編譯'HackALU()',優化級別爲1,2或3,那麼在堆棧中沒有爲'result'保留的內存變量。一切都在寄存器中完成。請親自看看:'gcc -c -O -S -o '。 – 2012-03-21 06:55:22

+0

真棒,這回答我的問題。 – Avi 2012-03-21 16:34:41

0

使用這個循環中,我實際上顯示的頂級版要快:

int n = 0; //optimization busting counter 
clock_t start = clock(); 
    for(word x=0; x<1000; ++x) { 
    for(word y=0; y<1000; ++y) { 
     for(int b = 0; b < 64; ++b) { 
      n += HackALU(x,y,b&0x1,b&0x2,b&0x4,b&0x8,b&0x10,b&0x20); 
} } } 
clock_t end = clock(); 
printf("finished, elapsed ticks = %d, n = %d\n", end - start, n); 

這是很明顯的頂配版本會少些說明,除非優化器是真的好,我不禁使其更快會要求減少分支或確保它們被準確預測。

1

邏輯變化會對代碼的性能產生較大的影響,而不是臨時對象的空白/存儲。

例如,有些機器沒有分支預測(PS3的SPU爲例),在這種情況下,你的代碼將是確實快用數學運算

word HackALU(word x, word y, bool zx, bool nx, bool zy, bool ny, bool f, bool no) 
{ 
    x = (zx == 0) * x; // [0 or 1] * x; 
    y = (zy == 0) * y; 

    x -= (nx != 0) * 2 * x; 
    y -= (ny != 0) * 2 * x; 

    word result = (f != 0) * (x + y) + (f == 0) * (x & y); 

    return (no != 0) * ~result + (no == 0) * result;  
}