GCC: извращения с вращением
А компилятор сделает лучше
Неоднократно встречаю такие объявления в заголовочных файлах (это особенно характерно для всяких «домашних» криптографических библиотек):
{
#if defined(__GNUC__) && defined(__i386__)
__asm__("roll %%cl,%0" :"=r" (x) :"0" (x),"c" (shift));
return x;
#else
return (x << shift) | (x >> (32 - shift));
#endif
}
Так вот: так делать не надо.
GCC сам по себе достаточно умный компилятор, и если целевой процессор поддерживает инструкции извращения вращения, то код будет оптимизирован должным образом.
Небольшое доказательство:
uint64_t rol64(uint64_t x, uint8_t n)
{
return (x >> n) | (x << (64 - n));
}
uint64_t ror64(uint64_t x, uint8_t n)
{
return (x >> (64 - n)) | (x << n);
}
uint32_t rol32(uint32_t x, uint8_t n)
{
return (x >> n) | (x << (32 - n));
}
uint32_t ror32(uint32_t x, uint8_t n)
{
return (x >> (32 - n)) | (x << n);
}
int main(void)
{
return 0;
}
Сборка на 64-битном процессоре:
даёт такой результат (оставлен только релевантный код):
mov ecx, esi
ror rdi, cl
mov rax, rdi
ret
ror64:
mov ecx, esi
rol rdi, cl
mov rax, rdi
ret
rol32:
mov ecx, esi
ror edi, cl
mov eax, edi
ret
ror32:
mov ecx, esi
rol edi, cl
mov eax, edi
ret
Если функции оформить как inline и вызывать их по мере надобности, то оптимизированный результат будет лучше, но речь не об этом — пример показывает, что GCC действительно в состоянии распознать искусственное вращение и оптимизировать его.
Теперь соберём программу ту же программу под 32-битную архитектуру:
Получим такой результат (64-битное вращение явно уступает 64-битному коду, но что поделать, это ограничение 32-битного набора инструкций):
push ebp
xor ebp, ebp
push edi
push esi
push ebx
movzx edi, BYTE PTR [esp+28]
mov eax, DWORD PTR [esp+20]
mov edx, DWORD PTR [esp+24]
mov ecx, edi
mov ebx, eax
mov esi, edx
shrd ebx, edx, cl
shr esi, cl
test cl, 32
mov ecx, 64
cmovne ebx, esi
cmovne esi, ebp
sub ecx, edi
mov ebp, edx
mov edi, eax
shld ebp, eax, cl
sal edi, cl
xor eax, eax
test cl, 32
cmovne ebp, edi
cmovne edi, eax
mov eax, edi
mov edx, ebp
or eax, ebx
or edx, esi
pop ebx
pop esi
pop edi
pop ebp
ret
ror64:
push ebp
xor edx, edx
push edi
push esi
push ebx
movzx eax, BYTE PTR [esp+28]
mov esi, DWORD PTR [esp+24]
mov ebx, DWORD PTR [esp+20]
mov ecx, eax
mov ebp, esi
mov edi, ebx
shld ebp, ebx, cl
sal edi, cl
test al, 32
mov ecx, 64
cmovne ebp, edi
cmovne edi, edx
sub ecx, eax
shrd ebx, esi, cl
xor eax, eax
shr esi, cl
test cl, 32
cmovne ebx, esi
cmovne esi, eax
mov edx, esi
mov eax, ebx
pop ebx
or eax, edi
or edx, ebp
pop esi
pop edi
pop ebp
ret
rol32:
movzx ecx, BYTE PTR [esp+8]
mov eax, DWORD PTR [esp+4]
ror eax, cl
ret
ror32:
movzx ecx, BYTE PTR [esp+8]
mov eax, DWORD PTR [esp+4]
rol eax, cl
ret
Я бы отказался от movzx в пользу mov cl, BYTE PTR [esp+8], но, возможно, что movzx используется из-за особенностей планирования инструкций для процессора.
Интересно было проверить генерируемый код при использовании быстрых типов: для этого я заменил uint32_t на uint_fast32_t и собрал 64-битную версию программы (очевидно, что для 32-битного кода такие переделки ничего не изменят: разрядность uint_fast32_t равно разрядности uint32_t (странно, да?), аналогично с uint_fast64_t и uint64_t).
В результате получилось, что не все йогурты одинаково полезны, и перед тем, как оптимизировать, нужно думать, стоит ли оно того:
movzx edx, sil
mov ecx, 32
mov rax, rdi
sub ecx, edx
sal rax, cl
mov ecx, edx
shr rdi, cl
or rax, rdi
ret
ror32:
movzx edx, sil
mov ecx, 32
mov rax, rdi
sub ecx, edx
shr rax, cl
mov ecx, edx
sal rdi, cl
or rax, rdi
ret
А мораль сей басни такова: не стоит делать ненужную работу — компиляторы нынче сами умные.
А еще ассемблерные вставки затрудняют работу оптимизатора: у gcc в этом случае могут возникнуть трудности с планированием инструкций.
Мар
2009
Комментарии к статье «GCC: извращения с вращением» (1) »
Пожалуйста, не используйте эту форму для комментирования! Данная форма предназначена исключительно для ботов.
Оставить комментарий к записи «GCC: извращения с вращением»
गते गते पारगते पारसंगते बोधि स्वाहा
Меня зовут Владимир, я программист-фрилансер, специализирующийся на Web-программировании и програмировании под Linux.
По совместительству занимаюсь администрированием LAMP/LNMP-серверов и техническим переводом.


Привет
У тебя интересный блог – «аффтар, пеши исчо» и не смотри на малое количество комментов %)