mm extract epi8 (...) intrinsic, который принимает в качестве аргумента не-литеральное целое число
В последнее время я использую SSE intrinsic int _mm_extract_epi8 (__m128i src, const int ndx), который, согласно ссылке "извлекает целочисленный байт из упакованного целочисленного элемента массива, выбранного индексом". Это именно то, чего я хочу.
Однако я определяю индекс через
_mm_cmpestri на _m128i, который выполняет упакованное сравнение строковых данных с явными длинами и генерирует индекс. Диапазон данного показателя составляет 0..16 где 0..15 представляет допустимый индекс, а 16 означает, что индекс не найден. Теперь, чтобы извлечь целое число в положение индекса я думал сделать следующее: const int index = _mm_cmpestri(...);
if (index >= 0 && index < 16) {
int intAtIndex = _mm_extract_epi8(..., index);
}
Это оставляет нас с ошибкой компилятора gcc (-O0):
Ошибка: селектор должен быть целочисленной константой в диапазоне 0..15
Неприятный способ обойти эту проблему-иметь switch на индексе и _mm_extract_epi8 вызов для каждого индекса в диапазоне 0..15. Мой вопрос в том, есть ли лучший/лучший способ, который я не вижу.
Обновление: с оптимизацией-O3 ошибки компиляции нет; все еще с-O0, хотя.
1 ответ:
Просто подведем итог и закроем вопрос.
Мы обсудили 3 варианта извлечения байта с индексом i в [0..15] из
_m128i sse, где я не могу быть сведен к литералу во время компиляции:1) переключатель &
_mm_extract_epi8: иметьswitchнад i и случай для каждого i в [0..15], что делает_mm_extract_epi8(sse,i); работает, как я сейчас является литералом времени компиляции.2) Union hack: иметь
union SSE128i { __m128i sse; char[16] array; }, инициализировать его какSSE128i sse = { _mm_loadu_si128(...) }и получить доступ к байту с индексом i с помощьюsse.array[i].3) перетасовать I-й элемент в позицию 0 и
Оценка: я провел сравнительный анализ трех вариантов архитектуры Intel Sandy Bridge и AMD Bulldozer. Возможность переключения выиграл с небольшим перевесом. Если кто-то заинтересован, я могу опубликовать более подробные цифры и настройки бенчмарка._mm_extract_epi8: Используйте_mm_shuffle_epi8(sse,_mm_set1_epi8(i))для перетасовки I-го элемента в позицию 0; извлеките его с помощью_mm_extract_epi8(sse,0).Обновление: Оценка Настройка бенчмарка: анализ каждого байта файла размером 1 ГБ. Для некоторых специальных байтов увеличьте счетчик. Используйте
_mm_cmpistri, чтобы найти индекс специальный байт; затем" извлеките " байт, используя один из трех упомянутых методов, и сделайте различие случаев, в котором счетчики увеличиваются. Код был скомпилирован с помощью GCC 4.6 с помощью-std=c++0x -O3 -march=native.Для каждого метода эталон был выполнен 25 раз на машине Sandy Bridge. Результаты (среднее и std. разработка. времени выполнения в секундах):
Переключение и извлечение: Среднее значение: 1071.45 Стандартное отклонение: 2.72006
Union hack: Среднее значение: 1078.61 Стандартное отклонение: 2.87131
Суффл и извлечение из позиции 0: Среднее значение: 1079.32 Стандартное отклонение: 2.69808
Различия незначительны. У меня еще не было возможности взглянуть на сгенерированный asm. Хотя было бы интересно увидеть разницу. На данный момент я не могу выпустить полный код бенчмарка, поскольку он содержит непубличные источники. Если у меня будет время, я извлеку их и опубликую источники.
Comments