作者 主題: g++ & clang++ compiler option -O1 & -O3 comparison  (閱讀 3738 次)

0 會員 與 1 訪客 正在閱讀本文。

Yamaka

  • 俺是博士!
  • *****
  • 文章數: 4913
    • 檢視個人資料
    • http://www.ecmagic.com
早上在修改一些 c++ 的東西,發現一個有趣的現象

下面是測試碼:

代碼: [選擇]
#include <iostream>
#include "microtime.h"

void swap(int &x, int &y) {
int tmp(x);
x = y;
y = tmp;
}

const int loopMax = 50000001;

int main() {
  int x = 24578, y = 2982;
  double t1 = microtime();
  for (int idx=0; idx<loopMax; ++idx) {
    swap(x, y);
  }
  t1 = microtime(t1);
  std::cout << "x, y = " << x << ", " << y
            << " [" << t1*1000 << "ms]\n";

  return 0;
}


本來是用 clang++ -O3 編譯,發現跑出來的時間怪怪的
於是就加 -S 看一下編出來的 asm code

代碼: [選擇]
fdivs .LCPI1_0(%rip)
    movl $50000002, %ecx         # imm = 0x2FAF082
    .align 16, 0x90
.LBB1_1:                                # =>This Inner Loop Header: Depth=1
    addl $-26, %ecx
    jne .LBB1_1
# BB#2:

哈~~~~~ 原來是騙局啦~~~
迴圈數還會偷偷加1呢~ ^_^

然後 cout 的地方
就直接將編譯器預估的結果印出來

 
代碼: [選擇]
    movl $2982, %esi             # imm = 0xBA6
    callq _ZNSolsEi
    movq %rax, %rbx
    movl $.L.str1, %esi
    movl $2, %edx
    movq %rbx, %rdi
    callq _ZSt16__ostream_insertIcSt11char_traitsIcEERSt13basic_ostreamIT_T0_ES6_PKS3_l
    movl $24578, %esi            # imm = 0x6002
    movq %rbx, %rdi
    callq _ZNSolsEi

所以根本就沒有真的跑 swap
連迴圈也是偷工減料來跑 XD

後來我改用 -O1 來編譯看看,另外也用 g++ 編

clang -O1:
 
代碼: [選擇]
    movl $50000001, %ebp         # imm = 0x2FAF081
    callq _Z9microtimee
    fstpt 16(%rsp)                # 10-byte Folded Spill
    leaq 60(%rsp), %r14
    leaq 56(%rsp), %rbx
    .align 16, 0x90
.LBB2_1:                                # =>This Inner Loop Header: Depth=1
    movq %r14, %rdi
    movq %rbx, %rsi
    callq _Z4swapRiS_
    decl %ebp
    jne .LBB2_1
# BB#2:

clang -O1 就有正常跑迴圈和呼叫 swap()
不過卻沒有自動將 swap() 編成 inline


g++ -O1:
代碼: [選擇]
    movl $50000001, %eax
    movl $24578, %ebx
    movl $2982, %ebp
    jmp .L12
.L13:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L12:
    subl $1, %eax
    jne .L13
   
.L13 ~ .L12 之間這3行就是實際執行 swap() 的動作

g++ -O3:
代碼: [選擇]
    movl $50000001, %eax
    fldl 40(%rsp)
    popq %rcx
    .c 72
    popq %rsi
    .cfi_def_cfa_offset 64
    jmp .L14
    .p2align 4,,10
    .p2align 3
.L15:
    movl %ebp, %edx
    movl %ebx, %ebp
    movl %edx, %ebx
.L14:
    subl $1, %eax
    jne .L15

swap() 的動作是在 .L15 ~ .L14

g++ -O1 或 -O3 都會正常編出迴圈
而且也會自動將 swap 編成 inline

下面是跑出來的結果

引用
$ ./ex044-clang++O1 && ./ex044-clang++O3 && ./ex044-g++O1 && ./ex044-g++O3
x, y = 2982, 24578 [1081.17ms]
x, y = 2982, 24578 [3.09399ms]
x, y = 2982, 24578 [402.601ms]
x, y = 2982, 24578 [339.092ms]

g++ 將 swap() 編成 inline
執行時就減少函數呼叫動作
因此會比 clang++ -O1 的碼快