GCC: извращения с вращением

Vladimir
Опубликовано в: C/C++

Неоднократно встречаю такие объявления в заголовочных файлах (это особенно характерно для всяких "домашних" криптографических библиотек):

[-]
View Code C
inline uint32_t rol(uint32_t x, uint8_t shift)
{
#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 сам по себе достаточно умный компилятор, и если целевой процессор поддерживает инструкции вращения, то код будет оптимизирован должным образом.

Небольшое доказательство:

[-]
Download test.c
#include <stdint.h>

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-битном процессоре:

[-]
View Code Bash
gcc -O3 -fomit-frame-pointer -masm=intel -S -c test.c -march=native -Wall

даёт такой результат (оставлен только релевантный код):

[-]
View Code ASM
rol64:
        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-битную архитектуру:

[-]
View Code Bash
gcc -O3 -fomit-frame-pointer -masm=intel -S -c test.c -march=native -m32 -Wall

Получим такой результат (64-битное вращение явно уступает 64-битному коду, но что поделать, это ограничение 32-битного набора инструкций):

[-]
View Code ASM
rol64:
        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).

В результате получилось, что не все йогурты одинаково полезны, и перед тем, как оптимизировать, нужно думать, стоит ли оно того:

[-]
View Code ASM
rol32:
        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

А мораль сей басни такова: не стоит делать ненужную работу — компиляторы нынче сами умные.

Добавить в закладки
  • del.ici.ous
  • Digg
  • Furl
  • Google
  • Simpy
  • Spurl
  • Y! MyWeb
  • БобрДобр
  • Мистер Вонг
  • Yandex.Закладки
  • Текст 2.0
  • News2
  • AddScoop
  • RuSpace
  • RUmarkz
  • Memori
  • Google Bookmarks
  • Писали
  • СМИ 2
  • Моё Место
  • 100 Закладок
  • Ваау!
  • Technorati
  • RuCity
  • LinkStore
  • NewsLand
  • Lopas
  • Закладки - IN.UA
  • Connotea
  • Bibsonomy
  • Trucking Bookmarks
  • Communizm
  • UCA
  • Slashdot
  • Magnolia
  • Blogmarks
  • Current
  • Meneame
  • Oknotizie
  • Diigo
  • Funp
  • Hugg
  • Dealspl.us
  • N4G
  • Mister Wong
  • Faves
  • Yigg
  • Fresqui
  • Care2
  • Kirtsy
  • Sphinn
  • SaveThis.ru

Связанные записи

22
Март
2009

Комментарии к статье «GCC: извращения с вращением» (1)  »

  1. йцукен says:

    Привет :)

    У тебя интересный блог - “аффтар, пеши исчо” и не смотри на малое количество комментов %)

Подписаться на RSS-ленту комментариев к статье «GCC: извращения с вращением» Trackback URL: http://blog.sjinks.org.ua/c-cpp/520-gcc-and-rotate-left-right/trackback/

Оставить комментарий к записи «GCC: извращения с вращением»

Вы можете использовать данные тэги: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>

Оставляя комментарий, Вы выражаете своё согласие с Правилами комментирования.

Подписаться, не комментируя