DSP編程技巧---不得不看的編譯指示
1. CHECK_MISRA
本文引用地址:http://dyxdggzs.com/article/201612/332356.htm它的作用與在編譯器選項中使用--check_misra是相同的,都是對特定源文件使能MISRA-C:2004規則檢查(汽車(chē)工業(yè)軟件可靠性聯(lián)會(huì )),使用方法是:
#pragma CHECK_MISRA (" {all|required|advisory|none|rulespec} ");
其中的rulespec是具體MISRA中的規則,使用方法請參考DSP編程技巧之12-揭開(kāi)編譯器神秘面紗之代碼規范MISRA-C。
2. CLINK
CLINK指令可用于某段代碼或者某個(gè)數據符號,使用之后會(huì )在包含被作用符號的段中產(chǎn)生一個(gè).clink指示,表明在條件鏈接的情況下,如果這個(gè)段沒(méi)有被其它任何段引用的話(huà),這個(gè)段可以被移除,從而減小鏈接輸出文件的尺寸。使用方法是:
#pragma CLINK (symbol )
3. CODE_ALIGN
CODE_ALIGN用來(lái)沿著(zhù)特定的對齊參數constant來(lái)對齊函數(從而可以讓CPU更快尋址,更快執行指令)。當我們希望函數從特定的邊界開(kāi)始的時(shí)候,這個(gè)指令非常有用。參數constant必須是2的冪(偶數對齊),使用方法是:
C代碼: #pragma CODE_ALIGN ( func, constant );
C++代碼: #pragma CODE_ALIGN ( constant );
注:在本文中,在C和C++代碼中,指令使用方法一樣時(shí),不分別寫(xiě)出,如不一樣則分C代碼和C++代碼分別寫(xiě)出。C代碼中的#pragma指令一般需指定函數名,也即其作用域;C++代碼中的#pragma指令一般不帶有函數名,其作用域為緊鄰該指令后面的函數;下同。
4. CODE_SECTION
CODE_SECTION是較為常見(jiàn)的指令,默認情況下,代碼被存放在.text段中,使用此指令則用來(lái)指定并改變某段代碼所分配的段,其使用方法是:
C代碼: #pragma CODE_SECTION (symbol , "section name ")
C++代碼: #pragma CODE_SECTION (" section name ")
例如:
char bufferA[80];
char bufferB[80];
#pragma CODE_SECTION(funcA, "codeA")
char funcA(int i);
char funcB(int i);
void main()
{
char c;
c = funcA(1);
c = funcB(2);
}
char funcA (int i)
{
return bufferA[i];
}
char funcB (int j)
{
return bufferB[j];
}
5. DATA_SECTION
DATA_SECTION可能是使用最多的pragma指令了,它用來(lái)定義存儲某個(gè)符號所使用的段,使用方法是:
C代碼: #pragma DATA_SECTION ( symbol , " section name ");
C++代碼: #pragma DATA_SECTION (" section name ");
例如:
#pragma DATA_SECTION(bufferB, "my_sect")
char bufferA[512];
char bufferB[512];
6. 與診斷信息有關(guān)的Pragma
診斷信息一般包括:提醒,警告,錯誤和不提示等幾個(gè)級別,使用與診斷信息有關(guān)的Pragma和使用相關(guān)的編譯器選項的結果是一樣的,其使用方法以及們的對應關(guān)系如下:
Pragma對應的編譯器選項
有關(guān)診斷信息的含義,請參考DSP編程技巧之7---揭開(kāi)編譯器神秘面紗之預處理與診斷。
7. FAST_FUNC_CALL
使用這個(gè)指令,會(huì )在編譯時(shí)調用快速匯編指令FFC,而不是傳統的CALL指令來(lái)完成函數的跳轉,其使用方法是:
#pragma FAST_FUNC_CALL ( func );
它的使用范圍是受限的:僅限于調用返回LB *XAR7指令的匯編程序。例如:
;匯編程序
_add_long:
ADD ACC, *-SP[2]
LB *XAR7
//調用匯編的C程序
#pragma FAST_FUNC_CALL (add_long);
long add_long(long, long);
void foo()
{
long x, y;
x = 0xffff;
y = 0xff;
y = add_long(x, y);
}
除此之外,如果使用該指令,編譯器會(huì )輸出警告信息,并忽略其指示。
8. FUNC_EXT_CALLED
在我們啟用程序級別的優(yōu)化選項時(shí)(-O3),所有未直接或者簡(jiǎn)介被main函數調用的函數都將被優(yōu)化掉,但是這些函數也有可能被我們定義的某些匯編代碼使用到,所以使用FUNC_EXT_CALLED可以在編譯時(shí)保留這些代碼,其使用方法是:
C代碼: #pragma FUNC_EXT_CALLED ( func );
C++代碼: #pragma FUNC_EXT_CALLED;
9. FUNCTION_OPTIONS
使用這個(gè)選項可以在編譯C/C++代碼中的某些函數時(shí),使用額外的編譯器的命令行選項,實(shí)現與在命令行中輸入相關(guān)的命令同樣的效果。其使用方法是:
C代碼: #pragma FUNCTION_OPTIONS ( func, "additional options" );
C++代碼: #pragma FUNCTION_OPTIONS( "additional options" );
10. INTERRUPT
使用這個(gè)選項可以在C代碼中直接操作中斷,其使用方法是:
C代碼: #pragma INTERRUPT ( func );
C++代碼: #pragma INTERRUPT ;
被該指令直接操作的函數將使用IRP(中斷返回指針)來(lái)返回值。
在使用FPU時(shí),中斷分為兩種:高優(yōu)先級中斷HPI和低優(yōu)先級中斷LPI,其中HPI使用快速的上下文存儲機制,不能被嵌套,LPI則與普通的C28x中斷機制一樣,并且可以被嵌套。此時(shí)可以增加第二個(gè)參數來(lái)控制:
C代碼: #pragma INTERRUPT ( func , {HPI|LPI} );
C++代碼: #pragma INTERRUPT ( {HPI|LPI} );在DSP/BIOS和SYS/BIOS HWI對象中,不能使用INTERRUPT指令,因為Hwi_enter/Hwi_exit宏和Hwi解包器已經(jīng)包含了該函數,此時(shí)使用該指令會(huì )產(chǎn)生負面的效果。
11. MUST_ITERATE
使用這個(gè)指令的情況下,我們確信某個(gè)for循環(huán)能夠執行指定的次數。使用這個(gè)指令能夠幫助編譯器確定循環(huán)的次數和最佳的實(shí)現方式,從而減小代碼的尺寸。其使用方法是:
#pragma MUST_ITERATE ( min, max, multiple );
min是循環(huán)的最小次數,max是最大執行次數,multiple則是循環(huán)次數的整數倍,如果這其中某個(gè)參數不存在,則可以省略,例如:
#pragma MUST_ITERATE(5); /* 最少循環(huán)5次 */
#pragma MUST_ITERATE(5, , 5); /* max參數省略;循環(huán)次數是5的倍數次(至少1倍) */
pragma MUST_ITERATE(8, 48, 8);
/* 循環(huán)此時(shí)可能為8, 16, 24, 32, 40, 48 */
12. NO_HOOKS
該指令阻止在調用函數時(shí)自動(dòng)產(chǎn)生進(jìn)入鉤子和退出鉤子,使用方法是:
C代碼: #pragma NO_HOOKS ( func );
C++代碼: #pragma NO_HOOKS;
13. RESET_MISRA
顧名思義,這個(gè)指令會(huì )把MISRA-C:2004規則檢查恢復到它原先的設定狀態(tài)。例如,某條規則在命令行里被使能,但是在某段代碼中被屏蔽了(某些原因導致它無(wú)法通過(guò)規則檢查),使用該指令會(huì )規則檢查重新使能。使用方法是:
#pragma RESET_MISRA (" {all|required|advisory|rulespec} ")
14. RETAIN
使用這個(gè)指令,可以避免某些符號在條件鏈接時(shí)被優(yōu)化掉,從而在輸出文件中保留它。使用方法是:
#pragma RETAIN ( symbol )
這個(gè)指令與我們的第二條,CLINK的效果是整好相反的。
15. SET_CODE_SECTION與SET_DATA_SECTION
這兩條指令用來(lái)設置其后所有聲明的段。使用方法是:
C代碼: #pragma SET_CODE_SECTION ("section name")
C++代碼: #pragma SET_DATA_SECTION ("section name")
例如:
#pragma SET_DATA_SECTION("mydata")
int x;
int y;
#pragma SET_DATA_SECTION()
其中的x和y都被會(huì )放入我們指定的段mydata中,直到我們使用空參數SET_DATA_SECTION(),之后的代碼或數據才會(huì )被放入默認的段之中。
16. UNROLL
UNROLL是“攤開(kāi)”的意思,這個(gè)指令與for/while相關(guān),意思是把n次的循環(huán)給展開(kāi),從而有個(gè)n份同樣的代碼。循環(huán)展開(kāi),是一種犧牲程序的尺寸來(lái)加快程序的執行速度的優(yōu)化方法??梢允謩?dòng)編程完成,也可由編譯器自動(dòng)優(yōu)化完成。循環(huán)展開(kāi)通過(guò)將循環(huán)體代碼復制多次實(shí)現。循環(huán)展開(kāi)能夠增大指令調度的空間,減少循環(huán)分支指令的開(kāi)銷(xiāo)。循環(huán)展開(kāi)可以更好地實(shí)現數據預取技術(shù)。其使用方法是:
#pragma UNROLL( n );
只有在編譯器認為n是安全的(即展開(kāi)之后確實(shí)都能執行),才能執行此操作。
評論