我最近在中斷服務例程 (ISR) 中遇到了這段代碼:
*(BUFFER_IDX[0] ) = *ADCVALS[0];
if (CHANNELS >= 1) {
*(BUFFER_IDX[1] ) = *ADCVALS[1];
if (CHANNELS >= 2) {
*(BUFFER_IDX[2] ) = *ADCVALS[2];
if (CHANNELS >= 3) {
*(BUFFER_IDX[3] ) = *ADCVALS[3];
}
}
}
它將 1-4 個暫存器值復制到記憶體中,具體取決于CHANNELS. 我發現它非常難看并將其更改為:
int i;
for (i = 0; i <= CHANNELS; i ) {
*(BUFFER_IDX[i] ) = *ADCVALS[i];
}
這立即破壞了 ISR。這是一個嵌入式系統,PIC16 架構,64 MHz 時鐘。ISR 受到嚴格的時間限制,必須在 1 μs 內完成。for 回圈顯然太慢了,而嵌套的 if 足夠快。
那么,我的問題有兩個方面:
- 在不減慢 ISR 的情況下,是否有一種不那么丑陋的方式來完成嵌套 if 子句的作業?
- 為什么 for 回圈這么慢?我本來希望編譯器(xc16)足夠聰明,可以為兩者(at
-O2)生成類似的 asm。
uj5u.com熱心網友回復:
for (int i = 0; i <= CHANNELS; i ) {
*(BUFFER_IDX[i] ) = *ADCVALS[i];
}
是
mov DWORD PTR [rbp-4], 0
jmp .L2
.L3:
mov eax, DWORD PTR [rbp-4]
cdqe
mov rax, QWORD PTR [rbp-80 rax*8]
mov edx, DWORD PTR [rax]
mov eax, DWORD PTR [rbp-4]
cdqe
mov rax, QWORD PTR [rbp-48 rax*8]
lea rsi, [rax 4]
mov ecx, DWORD PTR [rbp-4]
movsx rcx, ecx
mov QWORD PTR [rbp-48 rcx*8], rsi
mov DWORD PTR [rax], edx
add DWORD PTR [rbp-4], 1
.L2:
mov eax, DWORD PTR [rbp-4]
cmp eax, DWORD PTR [rbp-8]
jle .L3
和
*(BUFFER_IDX[0] ) = *ADCVALS[0];
if (CHANNELS >= 1) {
*(BUFFER_IDX[1] ) = *ADCVALS[1];
if (CHANNELS >= 2) {
*(BUFFER_IDX[2] ) = *ADCVALS[2];
if (CHANNELS >= 3) {
*(BUFFER_IDX[3] ) = *ADCVALS[3];
}
}
}
是
mov rax, QWORD PTR [rbp-80]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-48]
lea rcx, [rax 4]
mov QWORD PTR [rbp-48], rcx
mov DWORD PTR [rax], edx
cmp DWORD PTR [rbp-4], 0
jle .L2
mov rax, QWORD PTR [rbp-72]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-40]
lea rcx, [rax 4]
mov QWORD PTR [rbp-40], rcx
mov DWORD PTR [rax], edx
cmp DWORD PTR [rbp-4], 1
jle .L2
mov rax, QWORD PTR [rbp-64]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-32]
lea rcx, [rax 4]
mov QWORD PTR [rbp-32], rcx
mov DWORD PTR [rax], edx
cmp DWORD PTR [rbp-4], 2
jle .L2
mov rax, QWORD PTR [rbp-56]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rbp-24]
lea rcx, [rax 4]
mov QWORD PTR [rbp-24], rcx
mov DWORD PTR [rax], edx
你如何看到嵌套的 if 會做更少的跳轉但當前的編譯器可以優化它并且使用 -O3 標志你會得到這樣的東西
mov eax, DWORD PTR [rsp 12]
test eax, eax
js .L2
mov rax, QWORD PTR [rsp 48]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rsp 16]
mov DWORD PTR [rax], edx
mov eax, DWORD PTR [rsp 12]
test eax, eax
jle .L2
mov rax, QWORD PTR [rsp 56]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rsp 24]
mov DWORD PTR [rax], edx
mov eax, DWORD PTR [rsp 12]
sub eax, 1
jle .L2
mov rax, QWORD PTR [rsp 64]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rsp 32]
mov DWORD PTR [rax], edx
mov eax, DWORD PTR [rsp 12]
cmp eax, 2
jle .L2
mov rax, QWORD PTR [rsp 72]
mov edx, DWORD PTR [rax]
mov rax, QWORD PTR [rsp 40]
mov DWORD PTR [rax], edx
mov eax, DWORD PTR [rsp 12]
.L2:
這與嵌套的 if-s 具有 - 相同的性能
uj5u.com熱心網友回復:
我會四處走動(因為我通常不會這么靠近金屬)。
switch( CHANNELS ) {
case 3: *(BUFFER_IDX[3] ) = *ADCVALS[3]; /* Fallthroughs all the way down */
case 2: *(BUFFER_IDX[2] ) = *ADCVALS[2];
case 1: *(BUFFER_IDX[1] ) = *ADCVALS[1];
default:*(BUFFER_IDX[0] ) = *ADCVALS[0];
}
這是“更漂亮”,并在分支與獲取/分配操作之間進行權衡。
如果熟悉匯編和性能代碼的人愿意(友好而溫和地)評估這個替代方案,那就太好了。
轉載請註明出處,本文鏈接:https://www.uj5u.com/caozuo/512565.html
標籤:C表现嵌入式打断图片
