我正在尝试为GCC编写内联x86-64程序集以有效地使用MULQ指令.MULQ将64位寄存器RAX与另一个64位值相乘.另一个值可以是任何64位寄存器(甚至是RAX)或内存中的值.MULQ将产品的高64位放入RDX,将低64位放入RAX.
现在,很容易表达一个正确的mulq作为内联汇编:
#include <stdint.h>
static inline void mulq(uint64_t *high, uint64_t *low, uint64_t x, uint64_t y)
{
asm ("mulq %[y]"
: "=d" (*high), "=a" (*low)
: "a" (x), [y] "rm" (y)
);
}
Run Code Online (Sandbox Code Playgroud)
此代码是正确的,但不是最佳的.MULQ是可交换的,所以如果y恰好在RAX中,那么离开原点y并进行乘法是正确的.但GCC不知道这一点,因此会发出额外的指令将操作数移动到预先定义的位置.我想告诉GCC它可以将任一输入放在任一位置,只要一个在RAX中结束而MULQ引用另一个位置.GCC有一个这样的语法,称为"多个替代约束".注意逗号(但是整个asm()被破坏了;见下文):
asm ("mulq %[y]"
: "=d,d" (*high), "=a,a" (*low)
: "a,rm" (x), [y] "rm,a" (y)
);
Run Code Online (Sandbox Code Playgroud)
不幸的是,这是错误的.如果GCC选择第二个替代约束,它将发出"mulq%rax".要清楚,请考虑以下功能:
uint64_t f()
{
uint64_t high, low;
uint64_t rax;
asm("or %0,%0": "=a" (rax));
mulq(&high, &low, 7, rax);
return high;
}
Run Code Online (Sandbox Code Playgroud)
编译gcc -O3 -c -fkeep-inline-functions mulq.c,GCC发出这个程序集:
0000000000000010 …Run Code Online (Sandbox Code Playgroud)