AVR GCC、汇编 C 存根函数、eor 和所需的常量值

AVR GCC, assembly C stub functions, eor and the required constant value

我有这个代码:

uint16_t swap_bytes(uint16_t x)
{
    asm volatile(
        "eor, %A0, %B0"     "\n\t"
        "eor, %B0, %A0"     "\n\t"
        "eor, %A0, %B0"     "\n\t"
        : "=r" (x)
        : "0" (x)
    );
    return x;
}

其中(通过 avr-gcc version 4.8.1-std=gnu99 -save-temps)转换为:

.global swap_bytes
    .type   swap_bytes, @function
swap_bytes:
/* prologue: function */
/* frame size = 0 */
/* stack size = 0 */
.L__stack_usage = 0
/* #APP */
 ;  43 "..\lib\own\ownlib.c" 1
    eor, r24, r25
    eor, r25, r24
    eor, r24, r25

 ;  0 "" 2
/* #NOAPP */
    ret
    .size   swap_bytes, .-swap_bytes

但是编译器会这样抱怨:

|65|Error: constant value required|
|65|Error: garbage at end of line|
|66|Error: constant value required|
|66|Error: garbage at end of line|
|67|Error: constant value required|
|67|Error: garbage at end of line|
||=== Build failed: 6 error(s), 0 warning(s) (0 minute(s), 0 second(s)) ===|

提到的行是带有 eor 命令的行。为什么编译器会遇到问题?寄存器甚至更高(>= r16),几乎所有操作都是可能的。 constant value required 对我来说听起来像是在期待文字......我不明白。

只是为了向未来的 google 员工澄清:

eor, r24, r25

在 eor 之后多了一个逗号。这应该写成:

eor r24, r25

我也鼓励您(再次)考虑使用 gcc 的 __builtin_bswap16。如果您不熟悉 gcc 'builtin' 函数,它们是编译器内置的函数,并且(尽管看起来像函数)通常是内联的。它们是由了解各种处理器的所有来龙去脉的人编写和优化的,并且可以考虑到您可能没有考虑过的事情。

我理解保持代码尽可能小的愿望。我承认有可能(以某种方式)您的特定处理器上的这个内置程序正在生成次优代码(我假设您已经检查过?)。另一方面,它可能会产生完全相同的代码。或者它可能会使用一些更聪明的技巧来做到这一点。或者它可能会交错来自周围代码的指令以利用流水线(或其他一些我从未听说过的特定于 avr 的东西,因为我不会说话 'avr')。

此外,请考虑以下代码:

int main()
{
   return __builtin_bswap16(12345);
}

您的代码总是需要 3 条指令来处理交换。但是,使用内置函数,编译器可以识别 arg 是常量,并在编译时而不是 运行 时计算值。没有比这更有效的了。

我还可以指出 "easier to support." 编写内联 asm 的好处很难正确完成。未来的维护者不愿意碰它,因为他们永远不确定它是如何工作的。当然,内置的将更加跨平台可移植。

还不服气?我的最后一个建议:即使在您修复了逗号之后,您的内联 asm 代码仍然不太正确。考虑这段代码:

int main(int argc, char *argv[])
{
   return swap_bytes(argc) + swap_bytes(argc);
}

因为你写swap_bytes的方式(即使用volatile),gcc必须计算两次值(见volatile的定义)。如果您省略了 volatile(或者如果您使用了正确执行此操作的内置函数),它会意识到 argc 不会更改并重新使用第一次调用的输出。我是否提到正确编写内联 asm 很困难?

我不知道您的代码、约束、专业水平或要求。也许您的解决方案确实是最好的。我最多能做的就是鼓励您在生产代码中使用内联 asm 之前认真思考。