DSP編程技巧之15-使用代碼優(yōu)化時必須考慮的五大問題
前面我們提到了使用編譯器的優(yōu)化選項進行不同級別的代碼優(yōu)化的方法(請參考http://www.ex-cimer.com/article/203169.htm)。俗話說“好馬配好鞍”,即使我們有了強大的代碼優(yōu)化工具,使得我們書寫的符合ANSI/ISO C/C++的代碼能被高效執(zhí)行,我們在寫代碼時也要考慮到一些必要的原則,從而既能實現(xiàn)代碼的優(yōu)化,也能保證代碼的安全,使得優(yōu)化操作不會讓我們的代碼產生預期之外的結果。下面我們就來看一下在使用代碼優(yōu)化時,必須考慮的五大問題。
本文引用地址:http://www.ex-cimer.com/article/255842.htm1. 小心使用匯編表達式
在C/C++代碼中,有時候一些操作難免會對某些CPU寄存器進行操作,此時要使用內嵌的匯編表達式,例如asm("EALLOW"),或者重置某個中斷的掩碼寄存器等。在優(yōu)化代碼時,編譯器會重新調整某些代碼段的順序,自己決定使用某些寄存器(例如AR0-AR7這樣的輔助寄存器),甚至刪除某些編譯器認為無用的變量、函數(shù)等,但是編譯器一般情況下并不會對內嵌的匯編代碼進行任何優(yōu)化(除非這段匯編代碼被編譯器認為是永遠不會執(zhí)行到的無用代碼),這就造成了編譯器的優(yōu)化效果在這段匯編代碼和它的上下文代碼中無法進行有效的優(yōu)化,特別是匯編代碼和C/C++代碼直接存在變量調用的情況下。所以非必要的情況下,要盡量避免C/C++和匯編語句的混用,如果確實需要的,也要在編譯之后檢查生成的匯編代碼是不是保證了我們代碼原意的完整性。
2. 為必要的內存存取使用volatile關鍵字
在C/C++代碼的編譯過程中,編譯器會分析數(shù)據(jù)流,從而盡量避免對存儲空間的直接存取。但是如果我們要在C/C++代碼中直接對內存地址進行操作的話,需要使用volatile關鍵字來定義變量,編譯器在優(yōu)化時不會對volatile類型的變量進行優(yōu)化。
例如,在下面的代碼中,循環(huán)的結束條件為指針指向的地址為0xFF:
unsigned int *ctrl;
while (*ctrl !=0xFF);
因為*ctrl是一個不變的表達式,這個循環(huán)會被優(yōu)化為一次內存讀取。為了正確實現(xiàn)我們的代碼意圖,需要把ctrl定義為volatile類型:
volatile unsigned int *ctrl
使用volatile類型定義的類型在調試的時候還有一個極大的優(yōu)勢,就是我們可以直接在CCS的debug窗口里改變變量的值,極大地方便我們的調試。
3. 小心使用Alias變量
Alias(別名)在一個變量可以被至少兩種方式存取的時候會用到,例如,當兩個指針指向同一塊區(qū)域或對象時,我們稱一個指針 alias 另一個指針。Alias變量的使用要非常謹慎,因為會涉及到非直接的引用,從而破壞了優(yōu)化效果。編譯器在優(yōu)化時會分析代碼來決定在哪些地方會產生alias引用,然后在保持代碼正確性的基礎上“保守”地優(yōu)化代碼。
一般情況下,編譯器會假設,如果一個本地變量的地址被傳遞給某個函數(shù),則這個函數(shù)有可能會通過指針操作改變這個本地變量的內容,但是這個函數(shù)不能在該地址被返回后仍然可以被別的指針操作所示使用,例如把這個本地變量的地址分配給一個全局變量或者返回它。如果這種假設被打破,則需要在編譯器選項里使用-ma強制編譯器按照最壞情況的別名引用來進行一定的優(yōu)化,在這種情況下,任何非直接的引用(例如使用指針)都可以引用到這個變量。
4. 何時使用--aliased_variables選項?
編譯器在優(yōu)化時會假設,任何變量的地址在作為參數(shù)被傳遞給某個函數(shù)時,都不會在調用它的函數(shù)里被任何Alias變量修改,例如:從函數(shù)返回地址,或者把地址分配給某個全局變量。但是如果我們使用管理類似下面操作的代碼的時候,就需要使用--aliased_variables選項來優(yōu)化代碼:
int *glob_ptr;
g()
{
int x = 1;
int *p = f(&x);
*p = 5; /* p是x的別名 */
*glob_ptr = 10; /* glob_ptr 也是 x的別名 */
h(x);
}
int *f(int *arg)
{
glob_ptr = arg;
return arg;
}
5. 含有FPU的器件:使用restrict關鍵詞來表明指針沒有被別名操作
在含有FPU浮點協(xié)處理器的器件中,當使用--opt_level=2(優(yōu)化寄存器、局部變量和全局變量的使用)的優(yōu)化級別時,優(yōu)化器會分析代碼的依賴性。為了更好地幫助優(yōu)化器完成內存的依賴關系,我們可以把指針、引用或者數(shù)組等的聲明中加入restrict關鍵詞。restrict關鍵詞是C99標準引入的,它會通知編譯器,所有修改該指針所指向內存中內容的操作都必須通過該指針來修改,而不能通過其它途徑(其它變量或指針)來修改。使用這一原則能幫助編譯器優(yōu)化某些代碼段,因為別名信息可以被更加快速地確認。使用restrict關鍵詞后因為可以執(zhí)行更多的FPU操作,而FPU操作與CPU是并行的,所以帶來的優(yōu)化效果是提高了性能和減小了代碼尺寸。
我們可以使用下面例子中的代碼來告訴編譯器,a和b永遠不會在函數(shù)foo中指向同一個地址,并且a和b的內存地址也不會互相覆蓋(說明它們沒有依賴性,可以并行執(zhí)行)。
void foo(float * restrict a, float * restrict b)
{
/* foo's code here */
}
或者
void foo(float c[restrict], float d[restrict])
{
/* foo's code here */
}
c++相關文章:c++教程
評論