I am studying MASM32, and I am learning about various shift instructions.
I could understand standard shift instructions like SHL, SHR and so on.
But I am not clear some complex shift instructions like VPSLLVD, VPSRAVD and so on.
My example debug informations looks like below in Visual studio (little endian).
And my example project is x86.
vpsllvd ymm5, ymm0, ymm1 ; logical shift left
; YMM0 = 000011C8000000E9-FFFFDC80FFFE9BB8-0000116400000001-000204E30003672C
; YMM1 = 000008AE00000384-0000005700000064-000000050000000A-00001E8100000BB8
; YMM5 = 0000000000000000-0000000000000000-00022C8000000400-0000000000000000
vpsravd ymm6, ymm0, ymm1 ; arimethic shift right
; YMM0 = 000011C8000000E9-FFFFDC80FFFE9BB8-0000116400000001-000204E30003672C
; YMM1 = 000008AE00000384-0000005700000064-000000050000000A-00001E8100000BB8
; YMM6 = 0000000000000000-FFFFFFFFFFFFFFFF-0000008B00000000-0000000000000000
I found shift algorithms for these, and I am trying to understand these result of shift instruction, but I can't understand yet.
https://www.felixcloutier.com/x86/vpsllvw:vpsllvd:vpsllvq
VPSLLVD (VEX.256 version)
COUNT_0 := SRC2[31 : 0];
(* Repeat Each COUNT_i for the 2nd through 7th dwords of SRC2*)
COUNT_7 := SRC2[255 : 224];
IF COUNT_0 < 32 THEN
DEST[31:0] := ZeroExtend(SRC1[31:0] << COUNT_0);
ELSE
DEST[31:0] := 0;
(* Repeat shift operation for 2nd through 7th dwords *)
IF COUNT_7 < 32 THEN
DEST[255:224] := ZeroExtend(SRC1[255:224] << COUNT_7);
ELSE
DEST[255:224] := 0;
DEST[MAXVL-1:256] := 0;
https://www.felixcloutier.com/x86/vpsravw:vpsravd:vpsravq
VPSRAVD (VEX.256 version)
COUNT_0 := SRC2[31 : 0];
(* Repeat Each COUNT_i for the 2nd through 8th dwords of SRC2*)
COUNT_7 := SRC2[255 : 224];
DEST[31:0] := SignExtend(SRC1[31:0] >> COUNT_0);
(* Repeat shift operation for 2nd through 7th dwords *)
DEST[255:224] := SignExtend(SRC1[255:224] >> COUNT_7);
DEST[MAXVL-1:256] := 0;
Could you explain how these shift instructions work with my example debug information, please?
Each dword of the second operand is shifted by the amount specified by the corresponding dword of the third operand. It's the same as the simple shift instructions you are already familiar with.
In your first example, most shift amounts are greater than 32 so the result is zero in those dwords. Let's look at the third block which has sensible values:
ymm0 = 00001164 00000001
shift by:
ymm1 = 00000005 0000000A
So result is (00001164 << 5) (00000001 << A) = 00022C80 00000400
For the right shift the inputs in the first block are positive so those get turned into zero and the second block is negative so those become -1 (FFFFFFFF
) due to arithmetic shift being signed. The result for the third block is (00001164 >> 5) (00000001 >> A) = 0000008B 00000000
.