ReBits 32 x4

В ReBits 32 рассматривалась задача обращения одного 32-битного целого в рамках набора команд P6. Обычно, код, который стоит оптимизировать, используется внутри циклов с большим числом повторений, и обрабатывает большое количество данных (если вычисления достаточно просты – как в нашем случае). SIMD расширения архитектуры x86 позволяют обрабатывать 2 (MMX), 4 (SSE) или 8 (AVX) 32-битных целых «за раз» одной командой. MMX не сулит большого преимущества относительно SSE (под SSE подразумеваются все семейства команд вплоть до SSE4.2), а AVX не поддерживается процессорами, имеющимися у меня в наличии. Поэтому далее рассматривается SSE (фактически два варианта: для SSE2 и SSSE3).

Ни трюк с lea, ни циклический сдвиг недоступны в рамках SSE, поэтому отталкиваться будем от варианта H1. Сравнивать будем с развёрнутым циклом, вызывающим H5. Тест заключался в 200-кратном прогоне массива в 32Мб.

Итак, вариант для SSE2.

  1. Перемещение данных по 16 байт происходит эффективнее, если адрес выровнен по 16 (остаток от деления на 16 равен 0), поэтому кусочки массива, выдающиеся за границы выравнивания, обрабатываются отдельными циклами, вызывающими H5.
  2. К регистрам SSE (xmm0 – xmm7) нельзя применять константы, заданные непосредственно в коде, поэтому маски стоит разместить в регистрах перед входом в основной цикл, делается это путём помещения 32 битов в РОН, из которого они перемещаются в младшую четверть xmm-регистра, а затем копируются в оставшиеся четверти (broadcast).
  3. Инвертированные маски хранить необязательно, так как есть команда pandn (and-not).
  4. Последний обмен (16-битных половинок) осуществляется комбинацией команд pshuflw/pshufhw.
  5. Команда prefetchnta в начале цикла «намекает» процессору, что полезно начать подгружать данные по указанному адресу, которые мы будем читать и писать. Это может увеличить скорость обработки больших массивов (сотни элементов и больше).

SSSE3 позволяет сократить и ускорить код благодаря наличию команды pshufb, позволяющей произвольно переставлять байты внутри 128-битного xmm-регистра. Уровень поддержки процессором тех или иных SIMD расширений можно проверить с помощью инструкции cpuid непосредственно или используя соответствующий интринсик, как в этом примере. Со стороны пользователя проверка выполняется, например, так

if (doesCpuSupport().SSE3) { /* do SSE3 code */ }

См. также, например, AMD cpuid reference. Результат тестирования представлен на диаграмме (Deneb не поддерживает SSSE3).

Реклама

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

%d такие блоггеры, как: