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)