有人能用简单的语言解释一下GCC文档中“Clobbers and Scratch Registers”这一部分吗?下面是一个虚构的平方和指令,它需要两个指向内存中浮点值的指针,并产生一个浮点寄存器输出。请注意,在asm参数中,x和y都出现了两次,一次用于指定访问的内存,一次用于指定asm使用的基本寄存器。通常情况下,您不会浪费一个寄存器来做这件事,因为GCC可以将同一个寄存器用于两个目的。然而,如果在此asm中同时使用%1和%3表示x并期望它们相同,则是愚蠢的。实际上,%3可能不是一个寄存器,它可能是指向x所指对象的符号内存引用。
这里是一个虚构的指令:*z++ = *x++ * *y++。请注意,由于汇编会修改x、y和z指针寄存器,因此必须将它们指定为输入/输出。
在第一个示例中,将
作为奖励,如何更改以下示例,以便无需使用
asm ("sumsq %0, %1, %2"
: "+f" (result)
: "r" (x), "r" (y), "m" (*x), "m" (*y));
这里是一个虚构的指令:*z++ = *x++ * *y++。请注意,由于汇编会修改x、y和z指针寄存器,因此必须将它们指定为输入/输出。
asm ("vecmul %0, %1, %2"
: "+r" (z), "+r" (x), "+r" (y), "=m" (*z)
: "m" (*x), "m" (*y));
在第一个示例中,将
*x
和*y
列在输入操作数中的目的是什么?同一文档还说明:
在第二个示例中,为什么要使用输入操作数部分?它的任何操作数都没有在汇编语句中使用。特别地,没有办法指定输入操作数被修改而不同时将其指定为输出操作数。
作为奖励,如何更改以下示例,以便无需使用
volatile
关键字?(来源: 此 SO 帖子)void swap_2 (int *a, int *b)
{
int tmp0, tmp1;
__asm__ volatile (
"movl (%0), %k2\n\t" /* %2 (tmp0) = (*a) */
"movl (%1), %k3\n\t" /* %3 (tmp1) = (*b) */
"cmpl %k3, %k2\n\t"
"jle %=f\n\t" /* if (%2 <= %3) (at&t!) */
"movl %k3, (%0)\n\t"
"movl %k2, (%1)\n\t"
"%=:\n\t"
: "+r" (a), "+r" (b), "=r" (tmp0), "=r" (tmp1) :
: "memory" /* "cc" */ );
}
提前致谢。我已经为此苦苦思索了两天。
"m" (*x), "m" (*y)
被添加为输入操作数,以确保在调用扩展汇编模板之前将 x 和 y 的值实现到内存中。如果您将它们省略,并通过寄存器传递地址,则不能保证代码生成器实际上已将数据写入指向 2 个寄存器的 x 和 y 的内存中。"m" (*x), "m" (*y)
输入约束确保在执行内联汇编之前,x 和 y 的值已经在内存中。这种情况可能会发生在某些代码结构和优化开启的情况下。 - Michael Petch