2
\$\begingroup\$

I have some code that performs (nearly) the opposite function of a pmovmskb.

It takes as input a 16-bit bitfield and expands it into 2 xmm registers.
(I'm limited to working with AVX1 code).

The code I've come up with is:

const SliverToSliceMask = 0x0001-0002-0004-0008-0010-0020-0040-0080

movdqu xmm14,[rip+SliverToSliceMask]    ;xmm14 = mask to isolate bits 0..7
movdqa xmm15,xmm14                      ;xmm15 = mask
pslldq xmm15,1                          ;convert mask from bit 0..7 to bit 8..15
and edx,r8d                             ;combine the two slivers
  //Now expand the sliver into a slice
movd xmm0, edx              ;xmm0 = sliver
pshuflw xmm0,xmm0,$00       ;Paste the sliver 4 times (expanding it to 8 bytes).
pshufd xmm0, xmm0, $50     ;Paste the sliver 2 more times (expanding it to 16 bytes)
movdqa xmm1,xmm0           ;make a copy,expanding it to 32 bytes (in 2 regs)
//now xmm0 and xmm1 are filled with 16 copies of the input sliver, mask out the bit
//that is intended per word
pand xmm0,xmm14             ;mask off the words for bit 0..7
pand xmm1,xmm15             ;mask off the words for bit 8..15
pcmpeqw xmm0,xmm14          ;set 1's to $FFFF and 0's to 0
pcmpeqw xmm1,xmm15          ;Thus expanding the sliver (1 bit per outer sliver) 
                            ;to a slice (16 bits per sliver)

Is there a way to optimize this code. I would esp. like to get rid of the memory access to fetch the mask.

\$\endgroup\$
1
\$\begingroup\$

Your code is SSE but not AVX, so here is the SSE version to generate the mask. The second part is same as yours. I modified it from my other code and NEVER tested:

; generate the bit mask
pcmpeqd         xmm15, xmm15  ; FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
psrlq           xmm15, 63     ; 00000000 00000001 00000000 00000001
movdqa          xmm14, xmm15  ;
psllq           xmm14, 17     ; 00000000 00020000 00000000 00020000
por             xmm15, xmm14  ; 00000000 00020001 00000000 00020001
movdqa          xmm14, xmm15
psllq           xmm14, 34     ; 00080004 00000000 00080004 00000000
por             xmm15, xmm14  ; 00080004 00020001 00080004 00020001
movdqa          xmm14, xmm15
psllq           xmm14, 4      ; 00800040 00200010 00800040 00200010
punpcklqdq      xmm15, xmm14  ; 00800040 00200010 00080004 00020001

; generate the second bit mask
movdqa          xmm15, xmm14
psllw           xmm15, 8      ; 80004000 20001000 08000400 02000100

; load and broadcast DX
movd            xmm0, edx     ; xmm0 = sliver
pshuflw         xmm0, xmm0, 0 ; xmm0 = sliver * 4
pshufd          xmm0, xmm0, 0 ; xmm0 = sliver * 8
movdqa          xmm1, xmm0

; apply the mask
pand            xmm0, xmm14   ; apply mask
pand            xmm1, xmm15   ; apply mask
pcmpeqw         xmm0,xmm14    ; mask to FFFF
pcmpeqw         xmm1,xmm15    ; mask to FFFF

If you are using AVX, you can omit those movdqa and the code will look better. The SSE version is long and I am not sure its better than a simple memory read, as your did.

| improve this answer | |
\$\endgroup\$
  • 2
    \$\begingroup\$ Welcome to Code Review! You have presented an alternative solution, but haven't reviewed the code. Please edit it to explain your reasoning (how your solution works and how it improves upon the original) so that everyone can learn from your thought process. \$\endgroup\$ – Toby Speight Jul 17 '18 at 8:38

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.