在GCC样式的扩展内联asm中,是否可以输出“虚拟化”布尔值,例如,携带旗帜?

时间:2010-02-20 08:17:04

标签: gcc assembly boolean flags 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;
}

然后它将非常有效地内联,但有一个缺陷。返回值通过通用寄存器的“接口”完成,值为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)必须进行修改甚至重构才能实现?

另外,虽然我在这里 - 有没有其他方法可以改进比较运算符的制定?

2 个答案:

答案 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。