为了在 amd64 上的 GCC 中获得可用的 128 位操作,我实现了一些内联函数。像 add_128_128_128。我想让编译器决定哪些寄存器用作输入和输出以获得最大的灵活性。所以,我使用了多个替代约束。
inline __uint128_t add_128_128_128(__uint128_t a, __uint128_t b) {
uint64_t a_hi = a >> 64;
uint64_t a_lo = a;
uint64_t b_hi = b >> 64;
uint64_t b_lo = b;
uint64_t retval_hi;
uint64_t retval_lo;
asm (
"\n"
" add %2, %0\n"
" adc %3, %1\n"
: "=r,r,r,r" (retval_lo)
, "=r,r,r,r" (retval_hi)
: "r,0,r,0" (a_lo)
, "0,r,0,r" (b_lo)
, "r,1,1,r" (a_hi)
, "1,r,r,1" (b_hi)
);
return ((__uint128_t)retval_hi) << 64 | retval_lo;
}
现在,生成的汇编程序输出为:
_Z11add_128_128oo:
movq %rdx, %rax
movq %rcx, %rdx
add %rdi, %rax
adc %rax, %rdx
ret
令我困惑的是如何修复 adc 指令。考虑到这一点,我得出了一个临时结论,即使匹配的约束也会得到“新”数字,这可以解释 %rax 是 %3 == %0 == %rax。那么,有没有办法告诉 GCC 只计算“r”约束?(我知道我可以通过放弃多个替代约束来让这个内联汇编工作。)
顺便说一句:GCC 的内联汇编有什么有用的文档吗?当涉及到有趣的东西时,带有零示例的官方手册在这种情况下没有任何用处。用谷歌搜索并没有让我找到任何东西。所有的howtos和东西都只是谈论琐碎的基本东西,但完全省略了更高级的东西,比如多个替代约束。