Оптимизировано извлечение 64-битного значения из регистра AVX2.

Я пытаюсь извлечь 64 бит из регистра __m256i. Пример моей текущей функции извлечения:

             byte     31                    16 15                    0
byte_result_vec        000D  000C  000B  000A   000H  000G  000F  000E

_mm256_packs_epi32 ->  0D0C  0B0A  0D0C  0B0A   0H0G  0F0E  0H0G  0F0E

_mm256_packus_epi16 -> DCBA  DCBA  DCBA  DCBA   HGFE  HGFE  HGFE  HGFE
                                         ^^^^                     ^^^^
_mm256_castsi256_si128   -> HGFE  HGFE  HGFE  HGFE

_mm256_extracti128_si256 -> DCBA  DCBA  DCBA  DCBA

_mm_cvtsi128_si32(byte_result_vec1) ->  ABCD

_mm_cvtsi128_si32(byte_result_vec2) ->  EFGH

Следующий код сдвигает 4x8 битов в позицию регистра 0-3 и извлекает 32 бита.

        byte_result_vec = _mm256_packs_epi32(byte_result_vec, byte_result_vec);
        byte_result_vec = _mm256_packus_epi16(byte_result_vec, byte_result_vec);
        __m128i byte_result_vec1 = _mm256_castsi256_si128(byte_result_vec);
        __m128i byte_result_vec2 = _mm256_extracti128_si256(byte_result_vec,1);
        const int res1 = _mm_cvtsi128_si32(byte_result_vec1);
        const int res2 = _mm_cvtsi128_si32(byte_result_vec2);
        result_array[j]       = res1;
        result_array[j+1]     = res2;

Код работает правильно, но медленно. Похоже, что копирование res1 и res2 в result_array занимает больше всего времени. Есть ли способ оптимизировать его?


person martin s    schedule 13.01.2014    source источник


Ответы (1)


Возможно этот вариант будет быстрее

/* byte_result_vec        000H  000G  000F  000E   000D  000C  000B  000A */
const __m256i shuffle_mask = _mm256_setr_epi8(0,  4,  8, 12, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 4, 8, 12, -1, -1, -1, -1, -1, -1, -1, -1);
/* abcdefgh               0000  0000  HGFE  0000   0000  0000  0000  DCBA */
const __m256i abcdefgh = _mm256_shuffle_epi8(byte_result_vec, shuffle_mask);
/* abcd                                            0000  0000  0000  DCBA */
const __m128i abcd = _mm256_castsi256_si128(abcdefgh);
/* efgh                                            0000  0000  HGFE  0000 */
const __m128i efgh = _mm256_extracti128_si256(abcdefgh, 1);
_mm_storel_epi64((__m128i*)&result_array[j], _mm_or_si128(abcd, efgh));
person Marat Dukhan    schedule 13.01.2014
comment
Я только что обнаружил, что есть дополнительная возможность оптимизации: можно заменить _mm256_castsi256_si128 + _mm256_extracti128_si256 + _mm_or_si128 одним _mm256_permutevar8x32_epi32, чтобы получить такой же цикл задержки. - person Marat Dukhan; 13.01.2014
comment
Можете ли вы сказать мне разницу между _mm256_castsi256_si128 и _mm256_castsf256_si128. Для первого требуется AVX2, а для второго только AVX. Почему нужно когда-либо использовать _mm256_castsi256_si128? - person Z boson; 05.09.2014
comment
_mm256_castsi256_si128 не работает и требует только AVX. Точно так же другие приведения не являются операциями, они отличаются только типами аргументов/результатов. - person Marat Dukhan; 05.09.2014
comment
Извините, я задал неправильный вопрос. Я имел в виду, в чем разница между _mm256_extractf128_si256 и _mm256_extracti128_si256. Я знаю, что эти приведения не нужны, просто чтобы сделать компилятор счастливым. Я имею в виду это stackoverflow.com/questions/25684454/ - person Z boson; 05.09.2014
comment
Процессоры Intel традиционно имеют отдельные файлы регистров и пути данных для целочисленных регистров и регистров с плавающей запятой. Таким образом, VEXTRACTI128 может быть реализован в целочисленной части ядра SIMD и связан с целочисленным файлом регистров SIMD, а VEXTRACTF128 - в части с плавающей запятой и связан с регистровым файлом FP ​​SIMD. Таким образом, если вы используете VEXTRACTI128 с данными, полученными в результате операции с плавающей запятой (и, таким образом, регистр находится в файле FP), может возникнуть задержка в несколько циклов для перемещения данных между частями ядра SIMD. - person Marat Dukhan; 05.09.2014
comment
Да, именно так я и думал. Это приводит к смене домена. - person Z boson; 05.09.2014