7

2つの128ビット符号なし整数をインラインamd-64asmと比較する次のC++コードがある場合:

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;
}

次に、非常に効率的にインライン化されますが、1つの欠陥があります。戻り値は、値が0または1の汎用レジスタの「インターフェイス」を介して行われます。これにより、2つまたは3つの不要な余分な命令が追加され、完全に最適化される比較操作が損なわれます。生成されたコードは次のようになります。

    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

「bool」の戻り値を持つ「setc%0」の代わりに「int」の戻り値を持つ「sbb%0、%0」を使用する場合でも、2つの追加の命令があります。

    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(およびこの形式のインラインasmの使用も可能にするIntel 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人がこの質問を閲覧しています。どうやら、この機能にはある程度の関心があります。

今、私は個人的に、インラインasmをまったく使用しないという考え方を支持しています。しかし、必要な場合、はい、(今)'出力'フラグを使用できます。

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 に答える