7

如果我有以下 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

如果我使用带有“int”返回值的“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 扩展的内联汇编很棒,否则。但我希望它在各个方面都与内在函数一样好。我希望能够以 CPU 标志或标志的状态形式直接返回布尔值,而不必将其“渲染”到通用寄存器中。

这是可能的,还是必须修改甚至重构 GCC(以及英特尔 C++ 编译器,它也允许使用这种形式的内联汇编)才能实现?

另外,当我在做的时候——还有其他方法可以改进我的比较运算符吗?

4

2 回答 2

7

差不多 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;

要理解=@ccc:输出约束(需要=)是类型,@cc后跟要使用的条件代码(在这种情况下c是引用进位标志)。

好的,对于您的具体情况,这可能不再是问题(因为 gcc 现在支持直接比较 128 位数据类型),但(目前)有 1,326 人查看了这个问题。显然对这个功能有些兴趣。

现在我个人赞成说根本不使用内联汇编的思想流派。但是,如果必须,是的,您可以(现在)“输出”标志。

FWIW。

于 2017-01-16T03:20:56.830 回答
6

我不知道如何做到这一点。您可能会或可能不会认为这是一种改进:

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
于 2010-02-21T08:26:15.567 回答