使用寄存器交换值

Swapping values using registers

本文关键字:交换 寄存器      更新时间:2023-10-16

我一直在读关于在不使用临时变量的情况下交换变量内容的文章,除了我发现的关于x86上汇编的XCHG指令的著名xor算法之外。所以我写了这个代码:

void swap(int *left, int *right){
__asm__ __volatile__(
        "movl %0, %%eax;"
        "movl %1, %%ebx;"
        :
        : "r" (*left), "r" (*right)
    );
__asm__ __volatile__(
        "xchg %eax, %ebx;"
            );
__asm__ __volatile__(
        "movl %%eax, %0;"
        "movl %%ebx, %1;"
        : "=r" (*left), "=r" (*right)
    );}

它确实有效,但后来我意识到XCHG指令根本没有必要。

void swap(int *left, int *right){
__asm__ __volatile__(
        "movl %0, %%eax;"
        "movl %1, %%ebx;"
        :
        : "r" (*left), "r" (*right)
    );
__asm__ __volatile__(
        "movl %%ebx, %0;"
        "movl %%eax, %1;"
        : "=r" (*left), "=r" (*right)
    );}

第二个函数也起作用,但似乎没有人提到使用寄存器交换变量,所以这段代码是否被认为是错误的,而实际上它并没有真正正常工作?我是不是错过了什么?

我知道这只适用于x86,但由于大多数人都有英特尔x86处理器,这段代码可以用于任何现实世界的编程吗?我意识到这可能不会比用一个临时变量进行常规交换更快,但我是从理论的角度提出问题的。如果在一次测试或面试中,有人要求我在不使用临时变量的情况下用C编写一个函数来交换x86机器的值,那么这段代码是有效的还是完全是垃圾?谢谢你。

有效,是。按照我的标准,你是一个没有雇用。

为什么?费用

std::swap可以很好地完成任务,而且可能足够快。您的代码将有更高的维护成本。

当然,出于性能原因,有时会陷入汇编程序
这不是其中之一。

首先,内联程序集在很多方面都被破坏了:

  • 滥用volatile,这并不意味着你想要什么
  • 你不会告诉编译器你破坏了寄存器。(这是可以修复的)
  • 编译器可以在内联汇编块之间自由插入代码

对于程序员和编译器来说,内联汇编都很难做到正确。

此外,内联汇编可能会通过非常小心的破解进行优化,但它会以损害优化器能力的方式影响编译器(寄存器分配、重新排序等),这通常会导致整体性能下降。我并不反对内联汇编(或编译器内部),但它需要非常小心的处理,这使得它在大多数情况下都不合理。

std::swap将编译为比这更高效的asm。

这段代码比编译器发出的代码慢,而且已经损坏。

它在不告诉编译器的情况下攻击EAX和EBX,并且很容易失败,尤其是在启用优化的情况下编译,但即使没有优化也不安全。

请参阅如何编写一小段内联gnu扩展程序集来交换两个整数变量的值?例如,在xchg周围更正asm,以及一个更好的版本,它只使用约束来用零asm指令交换C变量,让编译器来确定它想要在哪个寄存器中使用哪个C变量。asm("" : "=r" (a), "=r" (b) : "1" (a), "0" (b));


即使您使用零asm语句和相反的输入/输出约束的内联asm,您仍然会破坏常量传播和范围分析,从而破坏优化。https://gcc.gnu.org/wiki/DontUseInlineAsm.我对前面链接的答案的编辑包括一个纯C交换,表明恒定传播在那里有效,但不适用于任何内联asm交换。

因此,即使是一个正确编写的版本,对于任何现实世界的使用来说仍然是无用的,除了作为一个练习/示例,为GNUC内联asm使用输入/输出约束,以避免在实际asm块的开始/结束处出现mov,并尽可能多地由编译器决定。


只有当你做了一些编译器无法做得比你个人更好的事情时,Asm才能赢得性能。(用于测试Collatz猜想的C++代码比手工编写的汇编更快——为什么?)

查看编译器的asm输出以获得正常函数(如何从GCC/clang汇编输出中消除"噪声"?),然后查看

  • https://agner.org/optimize/
  • 以及在预测现代超标量处理器上的操作延迟时需要考虑哪些因素,以及我如何手动计算它们

了解更多关于高效asm的原因。