AVR GCC 上的内联汇编优化问题 (ATTiny1614)
Inline assembly optimisation problem on AVR GCC (ATTiny1614)
我正在尝试为 ATtiny1614 开发延迟功能(使用 AtmelStudio 7)
有一个现有的平台 _delay_us() 可以做类似的事情,但这是一种学习经验,可以调整您自己的代码。
为了延迟分辨率和最小且一致的延迟时间,我决定采用内联汇编。
我做了以下内容:(片段)
__attribute__((__always_inline__)) static inline void delay_loops(volatile uint32_t numLoops) {
asm volatile(
"loop_1%=: \n\t"
" subi %A[numLoops], 1 \n\t"
" sbci %B[numLoops], 0 \n\t"
" sbci %C[numLoops], 0 \n\t"
" sbci %D[numLoops], 0 \n\t"
" brcc loop_1%= \n\t"
:
:[numLoops] "d" (numLoops)
// d=select upper register (r16-31) only
);
}
int main(void)
{
...
delay_loops(10);
delay_loops(12);
...
}
到目前为止,还不错。一切都按预期工作,并生成以下代码:
3ec: 8a e0 ldi r24, 0x0A ; 10
3ee: 90 e0 ldi r25, 0x00 ; 0
3f0: a0 e0 ldi r26, 0x00 ; 0
3f2: b0 e0 ldi r27, 0x00 ; 0
000003f4 <loop_1333>:
3f4: 81 50 subi r24, 0x01 ; 1
3f6: 90 40 sbci r25, 0x00 ; 0
3f8: a0 40 sbci r26, 0x00 ; 0
3fa: b0 40 sbci r27, 0x00 ; 0
3fc: d8 f7 brcc .-10 ; 0x3f4 <loop_1333>
3fe: 8c e0 ldi r24, 0x0C ; 12
400: 90 e0 ldi r25, 0x00 ; 0
402: a0 e0 ldi r26, 0x00 ; 0
404: b0 e0 ldi r27, 0x00 ; 0
00000406 <loop_1341>:
406: 81 50 subi r24, 0x01 ; 1
408: 90 40 sbci r25, 0x00 ; 0
40a: a0 40 sbci r26, 0x00 ; 0
40c: b0 40 sbci r27, 0x00 ; 0
40e: d8 f7 brcc .-10 ; 0x406 <loop_1341>
寄存器预加载给定的循环值,然后迭代该循环数。
但是,如果我将主要代码更改为
int main(void)
{
...
delay_loops(12); // changed 10->12
delay_loops(12);
...
}
然后第二个延迟似乎变得无穷无尽(或者至少超出了我的逻辑分析器的范围)。
编译后的程序集显示以下内容:
3ec: 8c e0 ldi r24, 0x0C ; 12
3ee: 90 e0 ldi r25, 0x00 ; 0
3f0: a0 e0 ldi r26, 0x00 ; 0
3f2: b0 e0 ldi r27, 0x00 ; 0
000003f4 <loop_1332>:
3f4: 81 50 subi r24, 0x01 ; 1
3f6: 90 40 sbci r25, 0x00 ; 0
3f8: a0 40 sbci r26, 0x00 ; 0
3fa: b0 40 sbci r27, 0x00 ; 0
3fc: d8 f7 brcc .-10 ; 0x3f4 <loop_1332>
000003fe <loop_1339>:
3fe: 81 50 subi r24, 0x01 ; 1
400: 90 40 sbci r25, 0x00 ; 0
402: a0 40 sbci r26, 0x00 ; 0
404: b0 40 sbci r27, 0x00 ; 0
406: d8 f7 brcc .-10 ; 0x3fe <loop_1339>
输入值 (12) 的初始化未在 delay_loops() 的第二个 'call' 上完成。程序集仅使用它仍然具有的(更改的)寄存器值继续第二个循环。
我只能假设编译器不知道我更改了 r24..27 并假设它们仍然正确初始化为 12,因此优化了正确的初始化。
如何强制正确初始化?
谢谢
inline assembler cookbook 解释了如果您将一个操作数用于输入和输出,您需要做什么。
按照他们的例子,我认为你应该尝试用这样的东西替换以冒号开头的两行:
:[numLoops] "=d" (numLoops)
:"0" (numLoops)
我正在尝试为 ATtiny1614 开发延迟功能(使用 AtmelStudio 7) 有一个现有的平台 _delay_us() 可以做类似的事情,但这是一种学习经验,可以调整您自己的代码。
为了延迟分辨率和最小且一致的延迟时间,我决定采用内联汇编。
我做了以下内容:(片段)
__attribute__((__always_inline__)) static inline void delay_loops(volatile uint32_t numLoops) {
asm volatile(
"loop_1%=: \n\t"
" subi %A[numLoops], 1 \n\t"
" sbci %B[numLoops], 0 \n\t"
" sbci %C[numLoops], 0 \n\t"
" sbci %D[numLoops], 0 \n\t"
" brcc loop_1%= \n\t"
:
:[numLoops] "d" (numLoops)
// d=select upper register (r16-31) only
);
}
int main(void)
{
...
delay_loops(10);
delay_loops(12);
...
}
到目前为止,还不错。一切都按预期工作,并生成以下代码:
3ec: 8a e0 ldi r24, 0x0A ; 10
3ee: 90 e0 ldi r25, 0x00 ; 0
3f0: a0 e0 ldi r26, 0x00 ; 0
3f2: b0 e0 ldi r27, 0x00 ; 0
000003f4 <loop_1333>:
3f4: 81 50 subi r24, 0x01 ; 1
3f6: 90 40 sbci r25, 0x00 ; 0
3f8: a0 40 sbci r26, 0x00 ; 0
3fa: b0 40 sbci r27, 0x00 ; 0
3fc: d8 f7 brcc .-10 ; 0x3f4 <loop_1333>
3fe: 8c e0 ldi r24, 0x0C ; 12
400: 90 e0 ldi r25, 0x00 ; 0
402: a0 e0 ldi r26, 0x00 ; 0
404: b0 e0 ldi r27, 0x00 ; 0
00000406 <loop_1341>:
406: 81 50 subi r24, 0x01 ; 1
408: 90 40 sbci r25, 0x00 ; 0
40a: a0 40 sbci r26, 0x00 ; 0
40c: b0 40 sbci r27, 0x00 ; 0
40e: d8 f7 brcc .-10 ; 0x406 <loop_1341>
寄存器预加载给定的循环值,然后迭代该循环数。
但是,如果我将主要代码更改为
int main(void)
{
...
delay_loops(12); // changed 10->12
delay_loops(12);
...
}
然后第二个延迟似乎变得无穷无尽(或者至少超出了我的逻辑分析器的范围)。
编译后的程序集显示以下内容:
3ec: 8c e0 ldi r24, 0x0C ; 12
3ee: 90 e0 ldi r25, 0x00 ; 0
3f0: a0 e0 ldi r26, 0x00 ; 0
3f2: b0 e0 ldi r27, 0x00 ; 0
000003f4 <loop_1332>:
3f4: 81 50 subi r24, 0x01 ; 1
3f6: 90 40 sbci r25, 0x00 ; 0
3f8: a0 40 sbci r26, 0x00 ; 0
3fa: b0 40 sbci r27, 0x00 ; 0
3fc: d8 f7 brcc .-10 ; 0x3f4 <loop_1332>
000003fe <loop_1339>:
3fe: 81 50 subi r24, 0x01 ; 1
400: 90 40 sbci r25, 0x00 ; 0
402: a0 40 sbci r26, 0x00 ; 0
404: b0 40 sbci r27, 0x00 ; 0
406: d8 f7 brcc .-10 ; 0x3fe <loop_1339>
输入值 (12) 的初始化未在 delay_loops() 的第二个 'call' 上完成。程序集仅使用它仍然具有的(更改的)寄存器值继续第二个循环。 我只能假设编译器不知道我更改了 r24..27 并假设它们仍然正确初始化为 12,因此优化了正确的初始化。
如何强制正确初始化?
谢谢
inline assembler cookbook 解释了如果您将一个操作数用于输入和输出,您需要做什么。
按照他们的例子,我认为你应该尝试用这样的东西替换以冒号开头的两行:
:[numLoops] "=d" (numLoops)
:"0" (numLoops)