gcc 的最佳化功能

GNU 的 gcc 編譯器,是 GNU 工具中最重要的程式之一,gcc 提供了四個層級的最佳化功能,包含完全不最佳化,以及 -O1, -O2, -O3等不同等級的最佳化功能,讓我們利用 –S 參數,將最佳化的結果以組合語言輸出,真槍實彈的觀察看看gcc的最佳化結果。

範例 4 顯示了一個具有函數 f() 的C語言程式,然而,函數f雖然做了一些計算,但傳回的值固定為14,我們用這個函數來測試 gcc 的最佳化能力,看看 gcc 最佳化能做到何種程度。

我們分別用 -O0 的無最佳化與 -O3 的最高等級最佳化進行編譯,其結果如範例 5 所示,讀者可以看到在第 2 欄的 optimize_O3.s 中,整個 f() 函數都不見了,只剩下movl $14, %eax 這個指令,直接將 f() 的傳回值 14 塞入到 %eax 暫存器,然後傳給 printf() 函數印出,這顯示了 gcc 的 –O3 編譯方式具有較好的最佳化能力。

範例 4. gcc 不同層級的最佳化實例 (optimize.c)

int main() {
  int x = f();
  printf("x=%d\n", x);
}

int f() {
  int a=3, b=4, c, d;
  c=a+b;
  d=a+b;
  return c+d;
}

範例 5. gcc 不同層級的最佳化實例 (optimize.c)

(a) 編譯指令(無最佳化):
指令:gcc -S optimize.c -o optimize_O0.s -O0
檔案:optimize_O0.s (無最佳化)
    .file    "optimize.c"
    .def ___main; .scl 2; .type 32;    .endef
    .section .rdata,"dr"
LC0:
    .ascii "x=%d\12\0"
    .text
.globl _main
    .def _main; .scl    2; .type 32; .endef
_main:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $24, %esp
    andl    $-16, %esp
    movl    $0, %eax
    addl    $15, %eax
    addl    $15, %eax
    shrl    $4, %eax
    sall    $4, %eax
    movl    %eax, -8(%ebp)
    movl    -8(%ebp), %eax
    call    __alloca
    call    ___main
    call    _f
    movl    %eax, -4(%ebp)
    movl    -4(%ebp), %eax
    movl    %eax, 4(%esp)
    movl    $LC0, (%esp)
    call    _printf
    leave
    ret
.globl _f
    .def _f; .scl 2; .type 32; .endef
_f:
    pushl    %ebp
    movl    %esp, %ebp
    subl    $16, %esp
    movl    $3, -4(%ebp)
    movl    $4, -8(%ebp)
    movl    -8(%ebp), %eax
    addl    -4(%ebp), %eax
    movl    %eax, -12(%ebp)
    movl    -8(%ebp), %eax
    addl    -4(%ebp), %eax
    movl    %eax, -16(%ebp)
    movl    -16(%ebp), %eax
    addl    -12(%ebp), %eax
    leave
    ret
    .def _printf; .scl 3; .type 32; .endef
    .def _f; .scl 3; .type 32; .endef
(b) 編譯指令(O3級最佳化):
指令:gcc -S optimize.c -o optimize_O3.s -O3
檔案:optimize_O3.s (有最佳化)
.file    "optimize.c"
    .text
    .p2align 4,,15
.globl _f
    .def _f; .scl 2; .type 32; .endef
_f:
    pushl    %ebp
    movl    $14, %eax
    movl    %esp, %ebp
    popl    %ebp
    ret
    .def ___main; .scl 2; .type 32; .endef
    .section .rdata,"dr"
LC0:
    .ascii "x=%d\12\0"
    .text
    .p2align 4,,15
.globl _main
    .def _main; .scl    2; .type 32; .endef
_main:
    pushl    %ebp
    movl    $16, %eax
    movl    %esp, %ebp
    subl    $8, %esp
    andl    $-16, %esp
    call    __alloca
    call    ___main
    movl    $LC0, (%esp)
    movl    $14, %eax
    movl    %eax, 4(%esp)
    call    _printf
    leave
    ret
    .def    _printf; .scl 3; .type 32; .endef
    .def _f; .scl 3; .type 32; .endef

在編譯器最佳化的議題上,有許多相關的研究與技術,若要更深入的理解這些技術,請進一步參考編譯器的相關書籍。

參考文獻

  1. Using and Porting the GNU Compiler Collection (GCC) — http://gcc.gnu.org/onlinedocs/gcc-2.95.3/gcc.html
  2. ARM CPU 的GNU 工具下載點位於http://www.gnuarm.com/files.html,筆者於寫作時其下載檔案連結為http://www.gnuarm.com/bu-2.15_gcc-3.4.3-c-c++-java_nl-1.12.0_gi-6.1.exe , 筆者存取時間點為 4/24/2009.
Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License