前言
人們在使用一個新的編程工具時總會感到缺乏自信本文試圖讓你對VC的代碼優化有更直觀的感覺希望你能通過閱讀本文從VC中得到更多的東西
Visual C++ NET
VCNET 不僅帶來了兩個新的優化選項它還改進了VCNET 中一些優化的性能
第一個新增選項是/G它告訴編譯器對Intel Pentium 和AMD Athlon處理器進行優化
使用/G選項編譯的程序當我們和VCNET 生成的代碼比較時發現它通常能使典型的程序的運行速度提高到個百分點如果使用了大量浮點代碼甚至能提高到個百分點而提高的優化程度可能很高也可能較低在一些使用最新CPU和/G選項的測試中甚至提高了%的性能
使用/G選項不代表生成的代碼只能運行在Intel Pentium 和AMD Athlon處理器上這些代碼仍可以運行在老的CPU上只是在性能表現上可能有小小的懲罰另外我們觀察到一些程序使用/G後在AMD Athlon上運行的比用Intel Pentium 更慢
當沒使用/Gx選項時編譯器會默認使用/GB選項此時為blended優化模式在VCNET 和VCNET 中/GB代表/G即為Intel Pentium Pro Pentium II Pentium III處理器優化
這兒有一個例子它展示了做與常整數乘法時使用Pentium 和/G的優化效果下面是源代碼
int i;
…
// Do something that assigns a value to i
…
return i*;
當使用/G時生成了目標代碼
mov eax DWORD PTR _i$[esp]
imul eax
當使用/G時生成了更快(可惜更長)的代碼它沒用imul(乘)指令在Pentium 上執行只需要個周期目標代碼如下
mov ecx DWORD PTR _i$[esp]
mov eax ecx
shl eax
sub eax ecx
第二個優化選項是/arch:[argument]用它可對SSE或SSE優化生成使用Streaming SIMD Extensions (SSE) 和 Streaming SIMD Extensions (SSE) 指令集的程序當使用/arch:SSE選項時目標代碼只能運行在支持SSE指令(如CMOV FCOMI FCOMIP FUCOMI FUCOMIP)的CPU上當使用/arch:SSE選項時目標代碼只能運行在支持SSE指令集的CPU上
相比於/G使用了SSE或SSE優化的程序一般能減少%的運行時間個別測試中甚至能減少%的運行時間
使用/arch:SSE可得到以下效果
在使用單精度浮點數時使用SSE指令對其處理
使用CMOV指令它最早被Pentium Pro支持
使用FCOMI FCOMIP FUCOMI FUCOMIP指令它們也是最早被Pentium Pro支持的
使用/arch:SSE的話可以得到所有/arch:SSE選項的效果另外還有以下幾個效果
在使用雙精度浮點數時使用SSE指令對其處理
使SSE指令集做位切換(原文Making use of SSE instructions for bit shifts)
還有其它的好處在同時使用/arch:SSE或/arch:SSE 和 /GL(全程優化)選項選項時編譯器會對浮點參數和浮點返回值做函數調用規則優化
上面說的幾點優化特性已經包括於VCNET 裡了另外還有一點就是能消除死參數從沒被用過的參數比如
int
f(int i int j int k)
{
return i + k;
}
int
main()
{
int n = a+b+c+d;
m = f( n );
return ;
}
在函數f()中第二個參數從沒被使用過當我們用/GL(全程優化)選項時編譯器將產生如下目標代碼來調用f()
mov eax
mov ecx
call ?f@@YAHHHH@Z
mov DWORD PTR ?m@@HA eax
在這個例子裡變量n從沒被運算只有兩個參數被f()使用所以只傳遞那兩個參數(並且它們是從寄存器傳過去的這比使用棧傳更快)另外編譯這個例子時要禁止內聯(inlining)否則函數f()就不存在了而直接給m賦予值
Visual C++ NET
VCNET 引入了全程優化(Whole Program Optimization縮寫為WPO)的概念/GL選項代表使用全程優化全程優化意味著編譯器在obj文件中存放的是代碼的中間表達而不是目標代碼在連接時連接器對其優化處理並生成真正的目標代碼
全程優化的一個主要好處在於我們可以跨越源文件進行函數內聯這將大大提高程序的性能還有一個好處在於編譯器可以跟蹤內存和寄存器的使用以便優化使函數調用的開銷更小
下面的代表展示了全程優化的表現
// File
extern void func (int * int *);
int g h;
int
main()
{
int i = ;
int j = ;
g = ;
h = ;
func(&I &j);
g = g + i;
h = h + i;
return ;
}
// File
extern int g;
extern int h;
void
func(int *pi int *pj)
{
*pj = g;
h = *pi;
}
當不使用/GL選項時生成了如下代碼
sub esp
lea eax DWORD PTR _j$[esp+]
push eax
lea ecx DWORD PTR _i$[esp+]
push ecx
mov DWORD PTR _i$[esp+]
mov DWORD PTR _j$[esp+]
mov DWORD PTR ?g@@HA
mov DWORD PTR ?h@@HA
call ?func@@YAXPAH@Z
mov eax DWORD PTR _i$[esp+]
mov edx DWORD PTR ?g@@HA
mov ecx DWORD PTR ?h@@HA
add edx eax
add ecx eax
mov DWORD PTR ?g@@HA edx
mov DWORD PTR ?h@@HA ecx
xor eax eax
add esp
ret
當使用了/GL時你會看到下面的代碼現在的代碼短多了注意編譯這個例子時同樣要注意關掉內聯優化
sub esp
lea ecx DWORD PTR _j$[esp+]
lea edx DWORD PTR _i$[esp+]
mov DWORD PTR _i$[esp+]
mov DWORD PTR ?g@@HA
mov DWORD PTR ?h@@HA
call ?func@@YAXPAH@Z
mov DWORD PTR ?g@@HA
xor eax eax
add esp
ret
From:http://tw.wingwit.com/Article/program/net/201311/11533.html