_mm_extract_epi8 (…) встроенная функция, которая принимает не буквальное целое число в качестве аргумента

Я в последнее время использую встроенный SSE 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, хотя.

3

Решение

Просто чтобы подвести итог и закрыть вопрос.

Мы обсудили 3 варианта извлечения байта с индексом i в [0..15] из _m128i sse где я не могу быть уменьшен до литерала во время компиляции:

1) Переключатель & _mm_extract_epi8: есть switch над i и случай для каждого i в [0..15], который делает _mm_extract_epi8(sse,i); работает как я сейчас является литералом времени компиляции.

2) Союз хакеров: есть union SSE128i { __m128i sse; char[16] array; }, инициализировать его как SSE128i sse = { _mm_loadu_si128(...) } и получить доступ к байту в индексе я с sse.array[i],

3) Переместите i-й элемент в положение 0 и _mm_extract_epi8: использовать _mm_shuffle_epi8(sse,_mm_set1_epi8(i)) переместить i-й элемент в положение 0; извлечь его с _mm_extract_epi8(sse,0),

Оценка: я сравнил три варианта для Intel Sandy Bridge и архитектуры AMD Bulldozer. Вариант переключения выиграл с небольшим отрывом. Если кому-то интересно, могу выложить более подробные цифры и настройки бенчмарка.

Обновление: оценка
Настройка бенчмарка: анализ каждого байта файла объемом 1 ГБ. Для определенных специальных байтов увеличьте счетчик. использование _mm_cmpistri найти индекс специального байта; затем «извлекают» байт, используя один из трех упомянутых методов, и проводят различие в регистре, в котором счетчики увеличиваются. Код был скомпилирован с использованием GCC 4.6 с -std=c++0x -O3 -march=native,

Для каждого метода тест 25 раз выполнялся на машине Sandy Bridge. Результаты (среднее и стандартное время работы в секундах):

Переключить и извлечь:
Среднее значение: 1071,45
Стандартное отклонение: 2.72006

Союз взломать:
Среднее значение: 1078,61
Стандартное отклонение: 2.87131

Суфле и извлечение из позиции 0:
Среднее значение: 1079,32
Стандартное отклонение: 2.69808

Различия незначительны. У меня еще не было возможности взглянуть на сгенерированный асм. Хотя может быть интересно увидеть разницу. На данный момент я не могу выпустить полный код теста, так как он содержит закрытые источники. Если у меня будет время, я извлечу их и выложу источники.

2

Другие решения

Других решений пока нет …

По вопросам рекламы [email protected]