2015-02-26 2 views
1

Этот вопрос связан с этим: Optimal uint8_t bitmap into a 8 x 32bit SIMD "bool" vectorсдвига элементов к слева от SIMD регистров на основе булевой маски

Я хотел бы создать оптимальную функцию с этой подписью:

__m256i PackLeft(__m256i inputVector, __m256i boolVector); 

желаемое поведение в том, что на вход 64-битной Int, например так:

inputVector = {42, 17, 13, 3}

boolVector = {истина, ложь, правда, ложь}

Он скрывает все значения, которые имеют false в boolVector, а затем проведет архивацию значения, которые остаются слева. На выходе выше, возвращаемое значение должно быть:

{42, 13, X, X}

... Где Х "Меня не волнует".

Очевидным способом сделать это является использование _mm_movemask_epi8, чтобы получить 8-байтовый int из вектора bool, посмотреть маску тасования в таблице и затем перетасовать маску.

Однако, если это возможно, я бы хотел избежать таблицы поиска. Есть ли более быстрое решение?

+1

Связанный: http://stackoverflow.com/questions/18708232/fast-compact-register-using-sse и http://stackoverflow.com/questions/25074197/compact-avx2-register-so-selected-integers -are-contiguous-matching-to-mask –

+0

@PaulR, если у вас есть 32-разрядное целое число с нулевым байтом, вы знаете умный способ сдвинуть нули? Я имею в виду, например, x01 00 00 05 -> 0x01 05 00 00 без обхода байтов? –

+0

Разве вы не хотите знать, сколько значений истинно? Если вы уже знаете это, это может быть полезным вкладом в вашу функцию.Если нет, мне кажется, что это должен быть выход. –

ответ

-1

Только что увидел эту проблему - возможно, вы ее уже решили, но я все еще пишу логику для других программистов, которым может понадобиться справиться с этой ситуацией.

Решение (в формате Intel ASM) приведено ниже. Он состоит из трех шагов:

Шаг 0: преобразуйте 8-битную маску в 64-битную маску, причем каждый бит набора в исходной маске представлен в виде 8 заданных бит в расширенной маске.

Шаг 1: Используйте эту расширенную маску, чтобы извлечь соответствующие биты из источника данных

Шаг 2: Поскольку вы требуете данные должны быть упакованы влево, мы перемещаем вывод по соответствующим количеством битов.

код, как показано ниже:

; Step 0 : convert the 8 bit mask into a 64 bit mask 
    xor  r8,r8 
    movzx rax,byte ptr mask_pattern 
    mov  r9,rax ; save a copy of the mask - avoids a memory read in Step 2 
    mov  rcx,8 ; size of mask in bit count 
outer_loop : 
    shr  al,1 ; get the least significant bit of the mask into CY 
    setnc dl  ; set DL to 0 if CY=1, else 1 
    dec dl  ; if mask lsb was 1, then DL is 1111, else it sets to 0000 
    shrd r8,rdx,8 
    loop outer_loop 
; We get the mask duplicated in R8, except it now represents bytewise mask 
; Step 1 : we extract the bits compressed to the lowest order bit 
    mov  rax,qword ptr data_pattern 
    pext rax,rax,r8 
; Now we do a right shift, as right aligned output is required 
    popcnt r9,r9 ; get the count of bits set in the mask 
    mov  rcx,8 
    sub  cl,r9b ; compute 8-(count of bits set to 1 in the mask) 
    shl  cl,3 ; convert the count of bits to count of bytes 
    shl  rax,cl 
;The required data is in RAX 

Trust это помогает

+0

[Никогда не используйте инструкцию LOOP] (http://stackoverflow.com/questions/35742570/why-is-the-loop-instruction-slow-couldnt-intel-have-implemented-it-efficiently), если вы хотите, чтобы ваш код для быстрого запуска. Поскольку вы используете BMI2 PEXT в любом случае, вам не нужен цикл! Вы можете PDEP с '0x0101 ...' и умножить на '0xFF', чтобы развернуть каждый бит в маске до полного байта all-0 или all-1. –

+1

Я думаю, что вы оставили восемь 8-битных целых чисел в одном 64-битном целое, чего не просил ОП. Однако такой метод может быть полезен для создания маски Shuffle для VPERMD. См. [Мой ответ AVX2 + BMI2 по вопросу с левой загрузкой] (http://stackoverflow.com/questions/36932240/avx2-what-is-the-most-efficient-way-to-pack-left-based-on -a-mask), где я использовал PDEP/PEXT + POPCNT для этого, с некоторым сходством с вашим кодом. (Но вместо обработки входных данных непосредственно с помощью PEXT, я использовал его на константе, а затем VPMOVZXBD, чтобы получить маску тасования). –

0

Это покрыто довольно хорошо Andreas Fredriksson в его 2015 GDC говорить: https://deplinenoise.files.wordpress.com/2015/03/gdc2015_afredriksson_simd.pdf

Начиная с горкой 104, он охватывает как это сделать, используя только SSSE3, а затем используя только SSE2.

+0

[С BMI2 вы можете создавать маски «на лету» для AVX2] (http://stackoverflow.com/questions/36932240/avx2-what-is-the-most-efficient-way-to-pack-left-based- на-маска). –

Смежные вопросы