Я только что заметил правку, в которой есть особый ответ.
Если вам нужно сделать много разных битовых позиций для одних и тех же данных, тогда ваш текущий план хорош.
Если вам нужна только одна битовая позиция (особенно самая высокая битовая позиция) из 128B памяти, вы можете использовать _mm256_movemask_ps
, чтобы получить старший бит из каждого элемента 32b. Затем объедините четыре 8-битные маски в регистрах GP.
Хороший компилятор должен оптимизировать это, чтобы:
vmovdqu ymm0, [buf + 0]
; to select a different bit:
; vpslld ymm0, ymm0, count ; count can be imm8 or the low byte of an xmm register
vmovmskps eax, ymm0
vmovdqu ymm0, [buf + 32]
vmovmskps ebx, ymm0
... ecx and edx
mov ah, bl
mov ch, dl
shl ecx, 16
or eax, ecx
Это хорошо, только если вы тестируете старший бит (так что вам не нужно сдвигать каждый вектор перед vmovmsk
). Тем не менее, это, вероятно, больше инструкций (и размера кода), чем другое решение.
Ответ на исходный вопрос:
Подобно идее Элальфера, но для pack
инструкций вместо pshufb
используйте блок перемешивания. Кроме того, все операторы AND независимы, поэтому они могут выполняться параллельно. Процессоры Intel могут выполнять 3 операции AND одновременно, но только в одном порядке. (Или сразу две перетасовки на pre-Haswell.)
// without AVX2: you won't really be able to
// do anything with a __m256i, only __m128i
// just convert everything to regular _mm_..., and leave out the final permute
mask = _mm256_set1_epi32(0x000000ff);
// same mask for all, and the load can fold into the AND
// You can write the load separately if you like, it'll still fold
L1 = and(mask, (buf)) // load and zero the bytes we don't want
L2 = and(mask, (buf+32))
L3 = and(mask, (buf+64))
L4 = and(mask, (buf+96))
// squish dwords from 2 concatenated regs down to words in 1 reg
pack12 = _mm256_packus_epi32(L1, L2);
pack34 = _mm256_packus_epi32(L3, L4);
packed = _mm256_packus_epi16(pack12, pack34); // note the different width: zero-padded-16 -> 8
Vec = permute(packed) // fix DWORD order in the vector (only needed for 256b version)
Vec = shift(Vec, bit_wanted)
bitvec = movemask(Vec)
// shift:
// I guess word or dword granularity is fine, since byte granularity isn't available.
// You only care about the high bit, so it doesn't matter than you're not shifting zeroes into the bottom of each byte.
// _mm_slli_epi32(Vec, imm8): 1 uop, 1c latency if your count is a compile-time constant.
// _mm_sll_epi32 (Vec, _mm_cvtsi32_si128(count)): 2uop 2c latency if it's variable.
// *not* _mm_sllv_epi32(): slower: different shift count for each element.
Если вы делаете это только с AVX (как вы сказали), тогда у вас не будет доступных целочисленных инструкций 256b. Просто постройте 128b векторов и получите 16b за один раз маскирования данных. В конце вам не понадобится окончательная перестановка.
Объединить маски с целочисленными инструкциями: (m2<<16) | m1
. При желании можно даже увеличить до 64 байт данных маски, объединив две маски 32 байт.
Производительность: это позволяет избежать необходимости в отдельных инструкциях по загрузке с AVX, поскольку vpand
может микро- объединить операнд памяти, если он используется с режимом однорегистровой адресации.
- цикл 1: 3
vpand
инструкций. (или только 2, если бы мы ждали адрес, так как порта загрузки всего 2.)
- цикл 2: последние один или два
vpand
, один pack
(L1, L2)
- цикл 3: следующий
pack
(L3, L4)
- цикл 4: финал
pack
- // 256b AVX2: переставить
- цикл 5: упакованный сдвиг с счетчиком imm8: 1 моп, задержка 1 с.
- цикл 6: маска движения (задержка в 3 цикла)
Задержка = 8 (SnB и выше)
Пропускная способность: 3 тасования (p5), 4 логических (p015), 1 смена (p0), 1 pmovmsk (p0). 4 загрузочных упа.
- SnB / IvB: 9 мопов ALU -> 3c. 4 чтения из памяти: 2c.
Итак, в зависимости от того, что вы делаете с масками, потребуется 3 аккумулятора для поддержания насыщения портов выполнения. (ceil (8/3) = 3.).
Со счетчиком сдвига в переменной, которая не может быть разрешена в константу времени компиляции путем встраивания / развертывания компилятора: задержка = 9. И сдвиг создает еще один uop для p1 / p5.
С AVX2 для Haswell и более поздних версий для vpermd
есть еще 3 дополнительных задержки.
person
Peter Cordes
schedule
18.08.2015