麻豆一区二区三区蜜桃免费_中文字幕Va一区二区三区 _国产成人综合久久二区_丰满多毛的大隂户毛茸茸_国产麻豆剧果冻传媒免费老狼_无码人妻精品一区二区三区久久久 _亚洲中文无码精品卡通_蜜臀亚洲AV永久无码精品老司机

【方輝專欄】ARM嵌入式編譯器(五) 優(yōu)化循環(huán)的4種方法
發(fā)布時(shí)間:2022-08-16

摘要: 本文主要對Arm Compiler 6編譯器的優(yōu)化循環(huán)對編寫優(yōu)化代碼的作用進(jìn)行介紹。

關(guān)鍵字:Arm Compiler 6、編譯器、優(yōu)化循環(huán) 、循環(huán)展開、pragma、循環(huán)向量化、循環(huán)終止、無限循環(huán)、


1. 循環(huán)展開

循環(huán)執(zhí)行的時(shí)間取決于循環(huán)的次數(shù),循環(huán)中每次檢查是否進(jìn)行循環(huán)的條件會(huì)降低循環(huán)的性能。使用循環(huán)展開可以減少檢查條件的判斷次數(shù),但是展開循環(huán)就意味著增加代碼量。例如:在精確的時(shí)鐘周期循環(huán)中,可以使用#pragma unroll (n)來展開循環(huán)。

“pragma”(編譯指示)僅在選擇優(yōu)化等級為-O2/-O3/-Ofast和-Omax時(shí)有效。

編譯指示的相關(guān)用法:

#pragma unroll (n)展開n次循環(huán)
#pragma unroll_completely展開所有循環(huán)

注:雖然給出了循環(huán)展開的編譯指示,但Arm官方不建議使用,這樣會(huì)影響編譯器的展開優(yōu)化和其他循環(huán)優(yōu)化。

不使用循環(huán)展開的代碼使用循環(huán)展開的代碼
int countSetBits1(unsigned int n)
{
int bits = 0;
while (n != 0)
{
if (n & 1) bits++;
n >>= 1;
}
return bits;
}
int countSetBits2(unsigned int n)
{
int bits = 0;
#pragma unroll (4)
while (n != 0)
{
if (n & 1) bits++;
n >>= 1;
}
return bits;
}

將代碼分別復(fù)制到file.c文件中,然后使用以下命令進(jìn)行編譯和反匯編。

armclang --target=arm-arm-none-eabi -march=armv8-a file.c -O2 -S -o file.s

不使用循環(huán)展開的匯編代碼使用循環(huán)展開的匯編代碼
countSetBits1:
mov r1, r0
mov r0, #0
cmp r1, #0
bxeq lr
mov r2, #0
mov r0, #0
.LBB0_1:
and r3, r1, #1
cmp r2, r1, asr #1
add r0, r0, r3
lsr r3, r1, #1
mov r1, r3
bne .LBB0_1
bx lr
countSetBits2:
mov r1, r0
mov r0, #0
cmp r1, #0
bxeq lr
mov r2, #0
mov r0, #0
LBB0_1:
and r3, r1, #1
cmp r2, r1, asr #1
add r0, r0, r3
beq .LBB0_4
@ BB#2:
asr r3, r1, #1
cmp r2, r1, asr #2
and r3, r3, #1
add r0, r0, r3
asrne r3, r1, #2
andne r3, r3, #1
addne r0, r0, r3
cmpne r2, r1, asr #3
beq .LBB0_4
@ BB#3:
asr r3, r1, #3
cmp r2, r1, asr #4
and r3, r3, #1
add r0, r0, r3
asr r3, r1, #4
mov r1, r3
bne .LBB0_1
.LBB0_4:
bx lr

可以看到展開循環(huán)時(shí),代碼執(zhí)行會(huì)更快,但代碼量也更大。


2. 循環(huán)向量化

如果編譯的目標(biāo)含有SIMD單元,那么編譯器就可以使用向量引擎來優(yōu)化代碼的向量部分。在優(yōu)化等級為-O1,可以使用-fvectorize 來啟動(dòng)優(yōu)化,而在-O2或更高等級時(shí)向量優(yōu)化是自動(dòng)啟用。

要使用向量優(yōu)化,在編寫代碼的時(shí)候需要將結(jié)構(gòu)體的成員放到同一個(gè)循環(huán)中,而不能使用獨(dú)立的循環(huán)。

可以進(jìn)行SIMD優(yōu)化的代碼不能進(jìn)行SIMD優(yōu)化的代碼
typedef struct tBuffer {
int a;
int b;
int c;
} tBuffer;
tBuffer buffer[8];
void DoubleBuffer1 (void)
{
int i;
for (i=0; i<8; i++)
{
buffer[i].a *= 2;
buffer[i].b *= 2;
buffer[i].c *= 2;
}
}
typedef struct tBuffer {
int a;
int b;
int c;
} tBuffer;
tBuffer buffer[8];
void DoubleBuffer2 (void)
{
int i;
for (i=0; i<8; i++)
buffer[i].a *= 2;
for (i=0; i<8; i++)
buffer[i].b *= 2;
for (i=0; i<8; i++)
buffer[i].c *= 2;
}

對于每個(gè)例子,將代碼分別復(fù)制到file.c文件中,然后使用以下命令進(jìn)行編譯和反匯編。

armclang --target=arm-arm-none-eabi -march=armv8-a file.c -O2 -S -o file.s

向量優(yōu)化后匯編代碼未進(jìn)行向量優(yōu)化的代碼
DoubleBuffer1:
.fnstart
@ BB#0:
movw r0, :lower16:buffer
movt r0, :upper16:buffer
vld1.64 {d16, d17}, [r0:128]
mov r1, r0
vshl.i32 q8, q8, #1
vst1.32 {d16, d17}, [r1:128]!
vld1.64 {d16, d17}, [r1:128]
vshl.i32 q8, q8, #1
vst1.64 {d16, d17}, [r1:128]
add r1, r0, #32
vld1.64 {d16, d17}, [r1:128]
vshl.i32 q8, q8, #1
vst1.64 {d16, d17}, [r1:128]
add r1, r0, #48
vld1.64 {d16, d17}, [r1:128]
vshl.i32 q8, q8, #1
vst1.64 {d16, d17}, [r1:128]
add r1, r0, #64
add r0, r0, #80
vld1.64 {d16, d17}, [r1:128]
vshl.i32 q8, q8, #1
vst1.64 {d16, d17}, [r1:128]
vld1.64 {d16, d17}, [r0:128]
vshl.i32 q8, q8, #1
vst1.64 {d16, d17}, [r0:128]
bxlr
DoubleBuffer2:
.fnstart
@ BB#0:
movw r0, :lower16:buffer
movt r0, :upper16:buffer
ldr r1, [r0]
lsl r1, r1, #1
str r1, [r0]
ldr r1, [r0, #12]
lsl r1, r1, #1
str r1, [r0, #12]
ldr r1, [r0, #24]
lsl r1, r1, #1
str r1, [r0, #24]
ldr r1, [r0, #36]
lsl r1, r1, #1
str r1, [r0, #36]
ldr r1, [r0, #48]
lsl r1, r1, #1
str r1, [r0, #48]
ldr r1, [r0, #60]
lsl r1, r1, #1
str r1, [r0, #60]
ldr r1, [r0, #72]
lsl r1, r1, #1
str r1, [r0, #72]
ldr r1, [r0, #84]
lsl r1, r1, #1
str r1, [r0, #84]
ldr r1, [r0, #4]
lsl r1, r1, #1
str r1, [r0, #4]
ldr r1, [r0, #16]
lsl r1, r1, #1
...
bx lr

在64位運(yùn)行狀態(tài)下要避免編譯器使用SIMD向量優(yōu)化可以在-march或-mcpu后+nosimd;

例如:

armclang --target=aarch64-arm-none-eabi -march=armv8-a+nosimd -O2 file.c -S -o file.s

在32位運(yùn)行狀態(tài)下要避免編譯器使用SIMD向量優(yōu)化,可以通過設(shè)置-mfpu=fp-armv8;

例如:

armclang --target=aarch32-arm-none-eabi -march=armv8-a -mfpu=fp-armv8 -O2 file.c -S -o file.s


3. 循環(huán)終止

在寫循環(huán)的時(shí)候如果編寫不當(dāng)會(huì)使得代碼的運(yùn)行效率降低和代碼量增大。建議使用以下的終止條件:

1)使用變量類型為:unsigned int

2)使用向下減少的計(jì)數(shù)方式,以減到0作為計(jì)數(shù)結(jié)束。

3)使用簡單的終止條件。

單獨(dú)或組合使用以上原則的終止條件,可以獲得更好的代碼大小或效率。

例如:這是一個(gè)實(shí)現(xiàn)n!的計(jì)算程序。

遞增循環(huán)遞減循環(huán)
int fact1(int n)
{
int i, fact = 1;
for (i = 1; i <= n; i++)
fact *= i;
return (fact);
}
int fact2(int n)
{
unsigned int i, fact = 1;
for (i = n; i != 0; i--)
fact *= i;
return (fact);
}

用以下命令反匯編以下armclang -Os -S --target=arm-arm-none-eabi -march=armv8-a

遞增循環(huán)遞減循環(huán)
fact1:
mov r1, r0
mov r0, #1
cmp r1, #1
bxlt lr
mov r2, #0
.LBB0_1:
add r2, r2, #1
mul r0, r0, r2
cmp r1, r2
bne .LBB0_1
bx lr
fact2:
mov r1, r0
mov r0, #1
cmp r1, #0
bxeq lr
.LBB1_1:
mul r0, r0, r1
subs r1, r1, #1
bne .LBB1_1
bx lr

對比反匯編代碼可以看出在遞減循環(huán)中用SUBS指令代替了遞增循環(huán)中ADD 和CMP兩條指令。這是因?yàn)镾UBS指令會(huì)自動(dòng)更新Z標(biāo)志。

此外在遞減循環(huán)中變量n不必再循環(huán)的過程實(shí)時(shí)使用,從而減少了寄存器的數(shù)量。

如果終止條件是一個(gè)函數(shù),則循環(huán)的每次都調(diào)用該函數(shù),這種情況下遞減的循環(huán)優(yōu)勢就更明顯了。例如:

for (...; i < get_limit(); ...);

說明:這種遞減循環(huán)計(jì)數(shù)的方式也適用于while-do 命令。


4. 無限循環(huán)

在某些情況下armclang會(huì)刪除一些編譯器認(rèn)為沒有影響的無限循環(huán),從而導(dǎo)致最終程序無法正常運(yùn)行。

為確保無限循環(huán)的正確編譯執(zhí)行,ARM官方建議在無限循環(huán)中添加__arm volatile的聲明。這個(gè)聲明的目的是告訴編譯器刪除這個(gè)無限循環(huán)會(huì)有影響,不能被優(yōu)化刪除。在無限循環(huán)中,把處理器設(shè)置為低功耗模式是一個(gè)不錯(cuò)的做法,當(dāng)有中斷或事件觸發(fā)時(shí)再回到正常模式。

下面是一個(gè)包含__arm volatile聲明的無限循環(huán)例子:

void infinite_loop(void) {

while (1)

??__asm volatile("wfe");

}


注:wfe(Wait for Event)是給處理器一個(gè)提示,使處理器進(jìn)入低功耗狀態(tài),直到事件或中斷觸發(fā)。


來源:《Arm? Compiler for Embedded User Guide Version 6.18》


+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++


關(guān)于億道電子

億道電子技術(shù)有限公司(英文名稱:Emdoor Electronics Technology Co.,Ltd)是國內(nèi)資深的研發(fā)工具軟件提供商,公司成立于 2002 年,面向中國廣大的制造業(yè)客戶提供研發(fā)、設(shè)計(jì)、管理過程中使用的各種軟件開發(fā)工具,致力于幫助客戶提高研發(fā)管理效率、縮短產(chǎn)品設(shè)計(jì)周期,提升產(chǎn)品可靠性。

20 年來,先后與 Altium、ARM、Ansys、QT、Adobe、Visu-IT、Minitab、Testplant、EPLAN、HighTec、GreenHills、PLS、Ashling、MSC Software 、Autodesk、Source Insight、TeamEDA、MicroFocus等多家全球知名公司建立戰(zhàn)略合作伙伴關(guān)系,并作為他們在中國區(qū)的主要分銷合作伙伴服務(wù)了數(shù)千家中國本土客戶,為客戶提供從芯片級開發(fā)工具、EDA 設(shè)計(jì)工具、軟件編譯以及測試工具、結(jié)構(gòu)設(shè)計(jì)工具、仿真工具、電氣設(shè)計(jì)工具、以及嵌入式 GUI 工具等等。億道電子憑借多年的經(jīng)驗(yàn)積累,真正的幫助客戶實(shí)現(xiàn)了讓研發(fā)更簡單、更可靠、更高效的目標(biāo)。

歡迎關(guān)注“億道電子”公眾號

了解更多研發(fā)工具軟件知識