为什么编译器不直接使用LSR

电器工程 Arduino avr-gcc
2022-01-08 23:40:55

嗨,我一直在使用 Arduino Uno(所以 ATmega328p)进行一个项目,其中时间非常重要,所以我想看看编译器将我的代码转换成哪些指令。在那里我有一个uint8_t我在每次迭代时向右移动一位data >>= 1,编译器似乎将它翻译成5条指令(datar24):

mov     r18, r24
ldi     r19, 0x00
asr     r19
ror     r18
mov     r24, r18

但是,如果我查看指令集文档,我会看到一条指令正是这样做的:lsr r24

我是否忽略了某些东西,或者为什么编译器也没有使用它?寄存器r18r19没有在其他任何地方使用。

我使用的是 Ardunio,但如果我是正确的,它只使用普通的avr-gcc编译器。这是生成序列的代码(修剪):

ISR(PCINT0_vect) {
    uint8_t data = 0;
    for (uint8_t i = 8; i > 0; --i) {
//        asm volatile ("lsr %0": "+w" (data));
        data >>= 1;
        if (PINB & (1 << PB0))
            data |= 0x80;
    }
    host_data = data;
}

据我所见,Ardunino IDE 使用的是系统提供的 AVR gcc 编译器,版本为 6.2.0-1.fc24。两者都是通过包管理器安装的,所以应该是最新的。

1个回答

根据 C 语言规范,任何大小小于int(取决于特定编译器;在您的情况下int为 16 位宽)涉及的任何操作(在您的情况下>>)的任何值都将向上转换为int操作之前的值。
编译器的这种行为称为整数提升

这正是编译器所做的:

  • r19=0 是 的整数提升值的 MSByte data
  • (r19, r18) 表示 的总整数提升值然后由data右移一位asr r19ror 18
  • 然后将结果隐式地转换回您的uint8_t变量data:
    mov r24, r18,即 r19 中的 MSByte 被丢弃。

编辑:
当然编译器可以优化代码。
试图重现该问题,我发现至少在 avr-gcc 版本 4.9.2 中不会出现该问题。它创建了非常高效的代码,即 C 行代码 data >>= 1;被编译成一条lsr r24指令。因此,也许您使用的是非常旧的编译器版本。