В GCC-стиле расширенный встроенный asm действительно ли возможно произвести “виртуализированное” булево значение, например, флаг переноса?

Если у меня есть следующий код 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

Если я использую "sbb %0, %0" с "международным" возвращаемым значением вместо "setc %0" с "bool" возвращаемым значением, существует все еще две дополнительных инструкции:

    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 (и компилятор Intel C ++, который также позволяет этой форме встроенного asm использоваться), должны быть изменены или даже пересмотрены для позволения?

Кроме того, в то время как я в нем — там какой-либо другой способ, которым могла быть улучшена моя формулировка сравнить оператора?

5
задан Deadcode 20 February 2010 в 09:22
поделиться

1 ответ

Я не знаю способа сделать это. Вы можете считать это улучшением, а можете и не считать:

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
4
ответ дан 14 December 2019 в 04:36
поделиться
Другие вопросы по тегам:

Похожие вопросы: