В настоящее время я экспериментирую с созданием высокооптимизированных многоразовых функций для моей библиотеки. Например, я пишу функцию "степень двойки" следующим образом:
template<class IntType>
inline bool is_power_of_two( const IntType x )
{
return (x != 0) && ((x & (x - 1)) == 0);
}
Это переносимая реализация с низким уровнем обслуживания в виде встроенного шаблона C ++. Этот код компилируется VC ++ 2008 в следующий код с ветвями:
is_power_of_two PROC
test rcx, rcx
je SHORT $LN3@is_power_o
lea rax, QWORD PTR [rcx-1]
test rax, rcx
jne SHORT $LN3@is_power_o
mov al, 1
ret 0
$LN3@is_power_o:
xor al, al
ret 0
is_power_of_two ENDP
Я нашел также реализацию отсюда: "The bit twiddler", который будет закодирован в сборка для x64 следующая:
is_power_of_two_fast PROC
test rcx, rcx
je SHORT NotAPowerOfTwo
lea rax, [rcx-1]
and rax, rcx
neg rax
sbb rax, rax
inc rax
ret
NotAPowerOfTwo:
xor rax, rax
ret
is_power_of_two_fast ENDP
Обе подпрограммы, написанные отдельно от C ++, я тестировал в сборочном модуле (файл .asm), а вторая работает примерно на 20% быстрее!
И все же накладные расходы на вызов функции значительны: если я сравниваю вторую реализацию сборки "is_power_of_two_fast" со встроенной версией функции шаблона, последняя работает быстрее, несмотря на ветвления!
К сожалению, в новых соглашениях для x64 указано, что встроенная сборка недопустима. Вместо этого следует использовать «внутренние функции».
Теперь вопрос: могу ли я реализовать более быструю версию is_power_of_two_fast как пользовательскую встроенную функцию или что-то подобное, чтобы ее можно было использовать встроенно? Или, в качестве альтернативы, можно ли каким-то образом заставить компилятор создавать версию функции с низкой ветвью?