淺談編譯器優化

黃志斌發表於2016-07-27

回顧

在“圖靈社群:檢測 2 的冪”中,我給出了以下函式:

int isPowerOf2a(long x)
{
  if (x <= 0) return 0;
  while (x % 2 == 0) x /= 2;
  return x == 1;
}

在二進位制計算機上,以上對 2 取模和除以 2 的運算可以使用按位與和向右移位運算代替:

while ((x & 1) == 0) x >>= 1;

在 Arch Linux 64-bit 作業系統中使用 clang 編譯器進行優化編譯後,得到以下結果:

$ clang -O isPowerOf2.c && ./a.out

isPowerOf2a:  49.7 seconds, 34
isPowerOf2b:  41.5 seconds, 34
isPowerOf2c:  29.7 seconds, 34
isPowerOf2d:  32.7 seconds, 34

反彙編

使用 objdump -d a.out 進行反彙編,經整理後得到:

可以看出,在 isPowerOf2a 函式中,clang 編譯器優化x % 2x & 1,避免了除法運算。但是,x /= 2被優化為以下 4 條指令(在此之前,已經執行了z = x):

  1. z >>>= 63; // z = (x < 0) ? 1 : 0;
  2. z += x;     // z = (x < 0) ? (x+1) : x;
  3. z >>= 1;   // z /= 2;
  4. x = z;

這是為了處理負整數的情形。負整數用二進位制補碼錶示時,算術右移 1 位的效果,相當於除以 2 時向負無窮大截斷。而在主流的 C 編譯器中,整數除法是向 0 截斷的。

如果能夠保證x是非負整數,x /= 2可以直接優化為x >>= 1。實際上,因為前面有:

if (x <= 0) return 0;

執行到這裡時,x必定是非負整數,但是 clang 編譯器的優化功能還沒有達到這個水平。

使用無符號整數

把 isPowerOf2.c 中的所有 long 修改為 unsinged long 後,再次編譯和執行,得到:

$ clang -O isPowerOf2u.c && ./a.out

isPowerOf2a:  38.1 seconds, 34
isPowerOf2b:  38.9 seconds, 34
isPowerOf2c:  25.0 seconds, 34
isPowerOf2d:  32.9 seconds, 34

使用 objdump -d a.out 進行反彙編,整理後得到:

 0:
 1:
 2:
 3:
 4:
 5:
 6:
 7:
 8:
 9:
10:
11:
0000000000400520 <isPowerOf2a>:
  400520:  xor    %eax,%eax
  400522:  test   %rdi,%rdi
  400525:  je     400544
  400530:  mov    %rdi,%rax
  400533:  shr    %rdi
  400536:  test   $0x1,%al
  400538:  je     400530
  40053a:  cmp    $0x1,%rax
  40053e:  sete   %al
  400541:  movzbl %al,%eax
  400544:  retq   
0000000000400550 <isPowerOf2b>:
  400550:  xor    %eax,%eax
  400552:  test   %rdi,%rdi
  400555:  je     400574
  400560:  mov    %rdi,%rax
  400563:  shr    %rdi
  400566:  test   $0x1,%al
  400568:  je     400560
  40056a:  cmp    $0x1,%rax
  40056e:  sete   %al
  400571:  movzbl %al,%eax
  400574:  retq 

可見,對於非負整數,clang 編譯器能夠很好地優化x /= 2x >>= 1。與上一小節的使用有符號整數的 isPowerOf2b 函式對比:

  • 第 3 行:jle指令改為je指令,即x <= 0改為x == 0
  • 第 5 行:sar指令改為shr指令,即算術右移改為邏輯右移

奇怪的是,isPowerOf2a 居然比 isPowerOf2b 更快,這沒道理啊,兩者的組合語言程式碼是一樣的。

相關文章