Dea*_*ode 5 assembly flags gcc boolean inline-assembly
如果我有以下C++代码来比较两个128位无符号整数,使用内联amd-64 asm:
struct uint128_t {
uint64_t lo, hi;
};
inline bool operator< (const uint128_t &a, const uint128_t &b)
{
uint64_t temp;
bool result;
__asm__(
"cmpq %3, %2;"
"sbbq %4, %1;"
"setc %0;"
: // outputs:
/*0*/"=r,1,2"(result),
/*1*/"=r,r,r"(temp)
: // inputs:
/*2*/"r,r,r"(a.lo),
/*3*/"emr,emr,emr"(b.lo),
/*4*/"emr,emr,emr"(b.hi),
"1"(a.hi));
return result;
}
Run Code Online (Sandbox Code Playgroud)
然后它将非常有效地内联,但有一个缺陷.返回值通过通用寄存器的"接口"完成,值为0或1.这会增加两个或三个不必要的额外指令,并减少比较操作,否则将完全优化.生成的代码看起来像这样:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15]
sbb r11, [r15+8]
setc al
movzx eax, al
test eax, eax
jnz is_lessthan
Run Code Online (Sandbox Code Playgroud)
如果我使用带有"bo"返回值的"sbb%0,%0"而不是带有"bool"返回值的"setc%0",那么还有两个额外的指令:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15]
sbb r11, [r15+8]
sbb eax, eax
test eax, eax
jnz is_lessthan
Run Code Online (Sandbox Code Playgroud)
我想要的是这个:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15]
sbb r11, [r15+8]
jc is_lessthan
Run Code Online (Sandbox Code Playgroud)
GCC扩展内联asm非常好,否则.但我希望它在各方面都能像内在函数一样好.我希望能够以CPU标志或标志的状态直接返回一个布尔值,而不必将其"渲染"到通用寄存器中.
这是可能的,还是GCC(以及英特尔C++编译器,也允许使用这种形式的内联asm)必须进行修改甚至重构才能实现?
此外,虽然我在这里 - 有没有其他方式我可以改进比较运算符的表述?
在这里,我们将近 7 年后,是的,gcc 终于添加了对“输出标志”的支持(在 6.1.0 中添加,于 2016 年 4 月发布)。详细的文档在这里,但简而言之,它看起来像这样:
/* Test if bit 0 is set in 'value' */
char a;
asm("bt $0, %1"
: "=@ccc" (a)
: "r" (value) );
if (a)
blah;
Run Code Online (Sandbox Code Playgroud)
要理解=@ccc:输出约束(需要=)的类型@cc后跟要使用的条件代码(在这种情况下c引用进位标志)。
好的,对于您的特定情况,这可能不再是问题(因为 gcc 现在支持直接比较 128 位数据类型),但是(目前)有 1,326 人查看了这个问题。显然有人对此功能感兴趣。
现在我个人赞成那种说根本不要使用内联汇编的思想流派。但是如果你必须,是的,你可以(现在)'输出'标志。
FWIW。
我不知道有什么方法可以做到这一点。您可能会也可能不会认为这是一种改进:
inline bool operator< (const uint128_t &a, const uint128_t &b)
{
register uint64_t temp = a.hi;
__asm__(
"cmpq %2, %1;"
"sbbq $0, %0;"
: // outputs:
/*0*/"=r"(temp)
: // inputs:
/*1*/"r"(a.lo),
/*2*/"mr"(b.lo),
"0"(temp));
return temp < b.hi;
}
Run Code Online (Sandbox Code Playgroud)
它产生类似的东西:
mov rdx, [r14]
mov rax, [r14+8]
cmp rdx, [r15]
sbb rax, 0
cmp rax, [r15+8]
jc is_lessthan
Run Code Online (Sandbox Code Playgroud)