如果我有以下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;
}
然后它将非常有效地内联,但有一个缺陷。返回值通过通用寄存器的“接口”完成,值为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
如果我使用带有“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
我想要的是:
mov r10, [r14]
mov r11, [r14+8]
cmp r10, [r15]
sbb r11, [r15+8]
jc is_lessthan
GCC扩展内联asm很棒,否则。但我希望它在各方面都能像内在函数一样好。我希望能够以CPU标志或标志的状态直接返回一个布尔值,而不必将其“渲染”到通用寄存器中。
这是可能的,还是GCC(和英特尔C ++编译器,也允许使用这种形式的内联asm)必须进行修改甚至重构才能实现?
另外,虽然我在这里 - 有没有其他方法可以改进比较运算符的制定?
答案 0 :(得分:4)
我不知道如何做到这一点。您可能会或可能不会认为这是一种改进:
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;
}
它产生类似的东西:
mov rdx, [r14]
mov rax, [r14+8]
cmp rdx, [r15]
sbb rax, 0
cmp rax, [r15+8]
jc is_lessthan
答案 1 :(得分:4)
这里我们差不多7年了,是的,gcc最后加入了对“输出标志”的支持(在6.1.0中添加,2016年4月发布)。详细的文档是here,但简而言之,它看起来像这样:
/* Test if bit 0 is set in 'value' */
char a;
asm("bt $0, %1"
: "=@ccc" (a)
: "r" (value) );
if (a)
blah;
要理解=@ccc
:输出约束(需要=
)的类型为@cc
,后跟要使用的条件代码(在本例中为c
来引用携带国旗)。
好的,这可能不再是您特定案例的问题(因为gcc现在支持直接比较128位数据类型),但(目前)已有1,326人查看了此问题。显然对此功能有一些兴趣。
现在我个人赞成don't use inline asm at all所说的思想流派。但如果你必须,是的你可以(现在)'输出'标志。
FWIW。