Если у меня есть следующий код 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 использоваться), должны быть изменены или даже пересмотрены для позволения?
Кроме того, в то время как я в нем — там какой-либо другой способ, которым могла быть улучшена моя формулировка сравнить оператора?
Я не знаю способа сделать это. Вы можете считать это улучшением, а можете и не считать:
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