Мне нужно использовать некоторые инструкции x86, которые не имеют встроенных функций GCC, такие как BSF и BSR.
Со встроенной сборкой GCC я могу написать что-то вроде следующего
__INTRIN_INLINE unsigned char bsf64(unsigned long* const index, const uint64_t mask)
{
__asm__("bsf %[mask], %[index]" : [index] "=r" (*index) : [mask] "mr" (mask));
return mask ? 1 : 0;
}
Код типа if (bsf64(x, y)) { /* use x */ }
переводится GCC на что-то вроде
0x000000010001bf04 <bsf64+0>: bsf %rax,%rdx
0x000000010001bf08 <bsf64+4>: test %rax,%rax
0x000000010001bf0b <bsf64+7>: jne 0x10001bf44 <...>
Однако, если mask
равно нулю, BSF уже устанавливает флаг ZF, поэтому test
после bsf
является избыточным.
Вместо возврата mask ? 1 : 0
возможно ли извлечь флаг ZF и вернуть его, чтобы GCC не генерировал test
?
РЕДАКТИРОВАТЬ: сделал пример if
более понятным
EDIT: В ответ на Damon, __builtin_ffsl
генерирует еще менее оптимальный код. Если я использую следующий код
int b = __builtin_ffsl(mask);
if (b) {
*index = b - 1;
return true;
} else {
return false;
}
GCC генерирует эту сборку
0x000000000044736d <+1101>: bsf %r14,%r14
0x0000000000447371 <+1105>: cmove %r12,%r14
0x0000000000447375 <+1109>: add $0x1,%r14d
0x0000000000447379 <+1113>: je 0x4471c0 <...>
0x000000000044737f <+1119>: lea -0x1(%r14),%ecx
Таким образом, test
пропал, но генерируются избыточные условные перемещения, приращения и убывания.