为什么这段代码是由 avr-gcc 生成的,它是如何工作的?

问题描述 投票:0回答:2

这是我正在开发的一个 C 项目中的反汇编 AVR 代码片段。我注意到生成了这个奇怪的代码,但我无法理解它是如何工作的。我假设这是某种荒谬的优化......

解释是什么?

92:         ticks++;         // unsigned char ticks;
+0000009F:   91900104    LDS       R25,0x0104     Load direct from data space
+000000A1:   5F9F        SUBI      R25,0xFF       Subtract immediate
+000000A2:   93900104    STS       0x0104,R25     Store direct to data space
95:         if (ticks == 0) {
+000000A4:   2399        TST       R25            Test for Zero or Minus
+000000A5:   F009        BREQ      PC+0x02        Branch if equal
+000000A6:   C067        RJMP      PC+0x0068      Relative jump

具体来说,为什么第二条指令从 R25 中减去 0xFF 而不是仅仅

INC R25

assembly optimization avr avr-gcc
2个回答
5
投票

SUBI 指令可用于将任何 8 位常数与 8 位值相加或相减。它与 INC 具有相同的成本,即指令大小和执行时间。所以SUBI是编译器首选的,因为它更通用。没有相应的ADDI指令,可能是因为它是多余的。


5
投票

tl;dr 编译器被设计为使用更便携、高效和通用的解决方案。

SUBI
指令集
C
(进位)和
H
(半进位)CPU标志用于后续指令(8位AVR BTW中没有
ADDI
,因此要添加立即数
x
的值我们减去
-x
它),而
INC
则不然。由于
SUBI
INC
都有 2 个字节的长度并在 1 个时钟周期内执行,因此使用
SUBI
不会丢失任何内容 - OTOH,如果您使用 8 位大小的计数器,您可以轻松检测它是否已翻滚(通过
BRCC
/
BRCS
),并且如果你有一个 16 位或 32 位大小的计数器,它允许你以一种非常简单的方式递增它 - 只需
INC
0x00FF
就会增加到
0x0000
,所以你必须在
0xFF
之前检查最低字节是否为
INC
。 OTOH,使用
SUBI
,您只需
SUBI -1
最低字节,然后
ADC 0
表示以下字节,确保所有潜在的进位位都已被考虑在内。

进一步阅读:

https://lists.gnu.org/archive/html/avr-gcc-list/2008-11/msg00029.html

http://avr-gcc-list.nongnu.narkive.com/SMMzdBkW/foo-subi-vs-inc

© www.soinside.com 2019 - 2024. All rights reserved.