以經典 3x3 矩陣乘法為例,在 VS2008 (x86) 環境下編譯,記錄 Debug(無優化)、Maximize Speed、Minimize Size 三種優化模式下的完整 x86 機器碼,展現編譯器如何從直譯源碼進化到指令級優化與程式碼壓縮。
void main() {
int a[3][3]={{1,1,1},{2,2,2},{3,3,3}};
int b[3][3]={{3,3,3},{2,2,2},{1,1,1}};
int c[3][3];
myfunction(a,b,c);
}
int myfunction(int a[3][3],int b[3][3],int c[3][3]) {
int i,j;
for(i=0;i<3;i++)
for(j=0;j<3;j++)
c[i][j]=a[i][0]*b[0][j]+a[i][1]*b[1][j]+a[i][2]*b[2][j];
return 0;
}
push ebp / mov ebp,esp),每個變數對應固定堆疊位移([ebp-XX])。mov dword ptr [ebp-XX], value,佔用大量指令空間。i, j 存儲於堆疊,每次迴圈皆 mov/inc/cmp/jcc 往返記憶體。imul edx, edx, 0C (乘 12 bytes/列) + 固定位移 (0, 4, 8) 取元素。printf 參數壓堆疊呼叫。push ebp 框架(Leaf function 最佳化),直接用 sub esp, 8 保留少量堆疊空間。mov eax,1/2/3 + mov [esp+offset], eax 批量寫入。add eax, 0C 直接指向 b[1][0]),內層迴圈中以 esi 走訪陣列欄,edi 走訪列,ebx 指向結果陣列 c。imul, add),僅最終結果 mov [ebx], eax 寫入記憶體。ebp (i) 與 ebp (j) 遞減至零 (sub/jnz),消除 cmp 指令。main 與 myfunction 合併為單一函數體,消除呼叫開銷。EBP+位移 定址([ebp+ecx*4-34]),以單一基址覆蓋多個陣列,減少指令編碼長度。inc ebx 替代 add ebx,4)。| 維度 | Debug | MaxSpeed | MinSize |
|---|---|---|---|
| 堆疊框架 | 完整 EBP | 無/精簡 | 完整 EBP |
| 變數存放 | 全堆疊 | 暫存器為主 | 堆疊+EBP相對 |
| 陣列存取 | 乘法+固定位移 | 預調基址+暫存器走訪 | EBP縮放索引定址 |
| 函數邊界 | 獨立 | 獨立 | 內聯合併 |
| 指令數 | 最多 | 中等 | 最少 |
| 適用場景 | 除錯 | 效能關鍵路徑 | 嵌入式/啟動碼 |