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, хотя.

572   1  

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 и _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. Результаты (среднее и std. разработка. времени выполнения в секундах):

Переключение и извлечение: Среднее значение: 1071.45 Стандартное отклонение: 2.72006

Union hack: Среднее значение: 1078.61 Стандартное отклонение: 2.87131

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

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

Comments

    Ничего не найдено.