Хабрахабр

Новая библиотека x86 SIMD интринсиков — immintrin debug

С каждым новым поколением процессоров Intel появляются новые и все более сложные векторные инструкции. Хотя длина вектора (512 бит) в ближайшее время расти не будет, появятся новые типы данных и виды инструкций. Например, кто сможет с первого взгляда понять, что делает такой интринсик (и соответствующая ему инструкция процессора)?

Bitwise ternary logic that provides the capability to implement any three-operand binary function; the specific binary function is specified by value in imm8.

__m512i _mm512_mask_ternarylogic_epi32 (__m512i src, __mmask8 k, __m512i a, __m512i b, int imm8)
FOR j := 0 to 15 i := j*32 IF k[j] FOR h := 0 to 31 index[2:0] := (src[i+h] << 2) OR (a[i+h] << 1) OR b[i+h] dst[i+h] := imm8[index[2:0]] ENDFOR ELSE dst[i+31:i] := src[i+31:i] FI
ENDFOR
dst[MAX:512] := 0

ОК, допустим, мы разобрались, как она работает. Следующий уровень сложности — отладка кода, интенсивно использующего такие интринсики.
Те, кто регулярно пользуются интринсиками, знают такой очень полезный сайт — Intel intrinsics guide. Если внимательно посмотреть, как он устроен, то легко заметить, что javascript фронтенд скачивает файл data-3.x.x.xml, в котором подробно описаны все интринсики, с кодом, похожим на Matlab. (Например, тот, что я скопировал в заголовке поста.)

Три месяца назад один клиент спросил меня, существует ли реализация векторных интринсиков на С для отладки, и я решил написать парсер, который транслирует код из Intrinsics Guide в С. Но когда мы используем интринсики для ускорения кода, мы пишем не на Matlab, а на С и С++! Получается библиотека, которая реализует почти все интринсики так, что пошаговым отладчиком можно заходить внутрь (или добавить отладочных printf).

Например, операция из заголовка поста превращается в

for (int j = 0; j <= 15; j++) } else { dst_vec[j] = src_vec[j]; }
}

Правда, так гораздо понятнее? Не очень? Ну, это я просто сложную функцию выбрал для примера. Обычно, когда отлаживаешь код с интринсиками, (например, DSP) приходится держать в голове как алгоритм, так и особенности каждой инструкции. Учитывая, что инструкции работают с длинными векторами, а DSP алгоритмы часто еще и основаны на серьезной математике, моя голова не справляется — кратковременной памяти и концентрации не хватает. Подозреваю, что я не одинок — несколько раз я даже думал, что нашел баг в инструкции. Потом, разумеется, каждый раз оказывалось, что ошибался я, и открыть новый FDIV bug не получилось. Но если бы я мог в тех случаях пошагово отлаживать внутри инструкции, я сразу же понял бы, при каких условиях в компоненте моего вектора появляется значение, которое я не ожидал.

Конечно, для этого гораздо лучше подходит Intel SDE — потому, что он предельно аккуратно имитирует все наборы инструкций. Клиенты мне говорили, что используют эту библиотеку для того, чтобы отлаживать отдельные функции с AVX-512 интринсиками на лэптопе, который поддерживает только AVX2. Как и положено юнит тестам, большинство работает как надо. У меня есть набор юнит тестов (тоже автоматически сгенерированных), которые для каждого интринсика из библиотеки сравнивают результат его работы с результатом исполнения соответствующей ассемблерной инструкции. Я бы сказал, что иногда получается эдакий -ffast-math. Но некоторые отладочные интринсики с плавающей точкой (и двойной, и одинарной точности) не всегда работают на 100% корректно. В IEE754 много тонкостей… А еще есть разные механизмы округления!

Если компилировать gcc или clang с опцией, например, -march=nehalem, то gcc и clang возвращают из функций 512-битные вектора на стеке, а ICC все равно возвращает их в ZMM0. Есть еще одна важная особенность использования immintrin debug вместо SDE (что я всячески не одобряю, но помешать этому не могу). А еще у gcc есть полезная опция -Og, которая помогает при отладке, в том числе с immintrin debug. Так что компилятор Intel в этом режиме использовать не получится.

Такие инструкции я не реализовал. Существует несколько интринсиков, главное действие которых — изменение содержимого регистра, например, или флагов. Ну и пока мой парсер не совсем готов, реализация еще примерно 10% интринсиков еще отсутствует.

Использовать immintrin debug очень просто — исходники менять не надо, но придется добавить условную компиляцию, чтобы включать immintrin_dbg.h вместо immintrin.h в случае отладочной сборки.

Скачать можно на гитхабе.

Теги
Показать больше

Похожие статьи

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

Ваш e-mail не будет опубликован. Обязательные поля помечены *

Кнопка «Наверх»
Закрыть