Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Optimization 为什么这个代码是由avr gcc生成的,它是如何工作的?_Optimization_Compiler Construction_Assembly_Avr_Avr Gcc - Fatal编程技术网

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

Optimization 为什么这个代码是由avr gcc生成的,它是如何工作的?,optimization,compiler-construction,assembly,avr,avr-gcc,Optimization,Compiler Construction,Assembly,Avr,Avr Gcc,这是我正在处理的一个C项目中反汇编的AVR代码片段。我注意到这个奇怪的代码正在生成,我无法理解它是如何工作的。我假设这是某种荒谬的优化 原因是什么 92: ticks++; // unsigned char ticks; +0000009F: 91900104 LDS R25,0x0104 Load direct from data space +000000A1: 5F9F SUBI R25,0xFF

这是我正在处理的一个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,而不是仅仅从R25中减去0xFF;dr编译器的设计目的是使用更具可移植性、高效性和通用性的解决方案

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

进一步阅读:


SUBI指令可用于将任何8位常量与8位值相加/相减。它的成本与INC相同,即指令大小和执行时间。因此,编译器更喜欢SUBI,因为它更通用。没有相应的ADDI指令,可能是因为它是冗余的。

如果不明显,我指的是第二行:从R25中减去0xFF。。。为什么不只是“INC R25”?正如@PeterCordes所指出的那样,这样的代码实际上只会通过
-O0
发出,这使得这个问题本身有点没有意义。。。使用
-O3
/
-Os
,这些指令将被更改为更紧凑的版本(分支上的标志等)。我包括了接下来的几个指令。。。这有助于缩小范围吗?我仍然不明白“SUBI R25,0xFF”和“INC R25”的区别,两者都是1个时钟。如果R25从255转为0,TST R25指令将正常工作。看起来INC设置了V、N、S、Z标志,但SUBI设置了H、V、N、S、Z、C。由于编译器接下来生成了一条TST指令,它似乎无论如何都没有使用SUBI的标志。此外,使用SUBI似乎有些奇怪,因为带有0x01的ADDI将再次等效。这真的有点神秘。我只是注意到没有ADDI指令。也许这可以部分解释。@GregHewgill我已经冒昧地(当然,如果你愿意,可以随意回滚)扩展了你的答案;因为你基本上是用这里的旗子打钉子,所以我添加了一些链接、基本原理等来证实它。我不想发布另一个答案,因为你基本上已经回答过了,但我觉得你的答案会更好,需要更多的幕后编译器琐事。@vaxquis:是的,我一直在看gcc asm输出(包括一个),我只是没有使用AVR的经验。你是对的,两者都有相同的大小/CPU时钟-但是说“
SUBI
是首选(…),因为它更通用”只是手工操作,没有描述任何细节
SUBI
并没有“更通用”,因为它需要寄存器r16-31,而不是
INC
的r0-31范围。avr gcc编译器被手动调整为执行
SUBI
而不是
INC
,原因正是下面格雷格给出的-
SUBI
正确设置进位标志,而
INC
只是忽略它。使用
SUBI
,它使16/32位计数器更加简单,因为您根本不必检查较低字节的溢出!