# X86 Assembly/SSE

SSE stands for Streaming SIMD Extensions. It is essentially the floating-point equivalent of the MMX instructions. The SSE registers are 128 bits, and can be used to perform operations on a variety of data sizes and types. Unlike MMX, the SSE registers do not overlap with the floating point stack.

## Registers

SSE, introduced by Intel in 1999 with the Pentium III, creates eight new 128-bit registers:
Originally, an SSE register could only be used as four 32-bit single precision floating point numbers (the equivalent of a float in C). SSE2 expanded the capabilities of the XMM registers, so they can now be used as:
* 2 64-bit floating points (double precision)
* 2 64-bit integers
* 4 32-bit floating points (single-precision)
* 4 32-bit integers
* 8 16-bit integers
* 16 8-bit characters (bytes)

## Data movement examples

The following program (using NASM syntax) performs data movements using SIMD instructions.

## Arithmetic example using packed singles

The following program (using NASM syntax) performs a few SIMD operations on some numbers.
The result values should be:
Using the GNU toolchain, you can debug and single-step like this:

### Debugger commands explained
#### break

    In this case, sets a breakpoint at a given label

#### stepi

    Steps one instruction forward in the program

#### p

    short for print, prints a given register or variable. Registers are prefixed by $ in GDB.

#### x

    short for examine, examines a given memory address. The "/4f" means "4 floats" (floats in GDB are 32-bits). You can use c for chars, x for hexadecimal and any other number instead of 4 of course. The "&" takes the address of v1, as in C.

## Shuffling example using shufps

shufps can be used to shuffle packed single-precision floats. The instruction takes three parameters, arg1 an xmm register, arg2 an xmm or a 128-bit memory location and IMM8 an 8-bit immediate control byte. shufps will take two elements each from arg1 and arg2, copying the elements to arg2. The lower two elements will come from arg1 and the higher two elements from arg2.

### IMM8 control byte description

IMM8 control byte is split into four group of bit fields that control the output into arg2 as follows:
* IMM8[1:0] specifies which element of arg1 ends up in the least significant element of arg2: IMM8[1:0] Description 00bCopy to the least significant element 01bCopy to the second element 10bCopy to the third element 11bCopy to the most significant element
* IMM8[3:2] specifies which element of arg1 ends up in the second element of arg2: IMM8[3:2] Description 00bCopy to the least significant element 01bCopy to the second element 10bCopy to the third element 11bCopy to the most significant element
* IMM8[5:4] specifies which element of arg2 ends up in the third element of arg2: IMM8[5:4] Description 00bCopy to the least significant element 01bCopy to the second element 10bCopy to the third element 11bCopy to the most significant element
* IMM8[7:6] specifies which element of arg2 ends up in the most significant element of arg2: IMM8[7:6] Description 00bCopy to the least significant element 01bCopy to the second element 10bCopy to the third element 11bCopy to the most significant element
IMM8 Example
Consider the byte 0x1B:
| Byte value | 0x1B | 0x1B | 0x1B | 0x1B | 0x1B | 0x1B | 0x1B | 0x1B |
| Nibble value | 0x1 | 0x1 | 0x1 | 0x1 | 0xB | 0xB | 0xB | 0xB |
| 2-bit integer (decimal) value | 0 | 0 | 1 | 1 | 2 | 2 | 3 | 3 |
| Bit value | 0 | 0 | 0 | 1 | 1 | 0 | 1 | 1 |
| Bit number (0 being LSB) | 7 | 6 | 5 | 4 | 3 | 2 | 1 | 0 |
The 2-bit values shown above are used to determine which elements are copied to arg2. Bits 7-4 are "indexes" into arg2, and bits 3-0 are "indexes" into the arg1.
* Since bits 7-6 are 0, the least significant element of arg2 is copied to the most significant elements of arg2, bits 127-96.
* Since bits 5-4 are 1, the second element of arg2 is copied to third element of arg2, bits 95-64.
* Since bits 3-2 are 2, the third element of arg1 is copied to the second element of arg2, bits 63-32.
* Since bits 0-1 are 3, the fourth element of arg1 is copied to the least significant elements of arg2, bits (31-0).
Note that since the first and second arguments are equal in the following example, the mask 0x1B will effectively reverse the order of the floats in the XMM register, since the 2-bit integers are 0, 1, 2, 3. Had it been 3, 2, 1, 0 (0xE4) it would be a no-op. Had it been 0, 0, 0, 0 (0x00) it would be a broadcast of the least significant 32 bits.
Example
Using GAS to build an ELF executable

## Text Processing Instructions

SSE 4.2 adds four string text processing instructions PCMPISTRI, PCMPISTRM, PCMPESTRI and PCMPESTRM. These instructions take three parameters, arg1 an xmm register, arg2 an xmm or a 128-bit memory location and IMM8 an 8-bit immediate control byte. These instructions will perform arithmetic comparison between the packed contents of arg1 and arg2. IMM8 specifies the format of the input/output as well as the operation of two intermediate stages of processing. The results of stage 1 and stage 2 of intermediate processing will be referred to as IntRes1 and IntRes2 respectively. These instructions also provide additional information about the result through overload use of the arithmetic flags(AF, CF, OF, PF, SF and ZF).
The instructions proceed in multiple steps:
* arg1 and arg2 are compared
* An aggregation operation is applied to the result of the comparison with the result flowing into IntRes1
* An optional negation is performed with the result flowing into IntRes2
* An output in the form of an index(in ECX) or a mask(in XMM0) is produced

### IMM8 control byte description

IMM8 control byte is split into four group of bit fields that control the following settings:
* IMM8[1:0] specifies the format of the 128-bit source data(arg1 and arg2): IMM8[1:0] Description 00bunsigned bytes(16 packed unsigned bytes) 01bunsigned words(8 packed unsigned words) 10bsigned bytes(16 packed signed bytes) 11bsigned words(8 packed signed words)
* IMM8[3:2] specifies the aggregation operation whose result will be placed in intermediate result 1, which we will refer to as IntRes1. The size of IntRes1 will depend on the format of the source data, 16-bit for packed bytes and 8-bit for packed words: IMM8[3:2] Description 00bEqual Any, arg1 is a character set, arg2 is the string to search in. IntRes1[i] is set to 1 if arg2[i] is in the set represented by arg1: arg1 = "aeiou" arg2 = "Example string 1" IntRes1 = 0010001000010000 01bRanges, arg1 is a set of character ranges i.e. "09az" means all characters from 0 to 9 and from a to z., arg2 is the string to search over. IntRes1[i] is set to 1 if arg[i] is in any of the ranges represented by arg1: arg1 = "09az" arg2 = "Testing 1 2 3, T" IntRes1 = 0111111010101000 10bEqual Each, arg1 is string one and arg2 is string two. IntRes1[i] is set to 1 if arg1[i] == arg2[i]: arg1 = "The quick brown " arg2 = "The quack green " IntRes1 = 1111110111010011 11bEqual Ordered, arg1 is a substring string to search for, arg2 is the string to search within. IntRes1[i] is set to 1 if the substring arg1 can be found at position arg2[i]: arg1 = "he" arg2 = ", he helped her " IntRes1 = 0010010000001000
* IMM8[5:4] specifies the polarity or the processing of IntRes1, into intermediate result 2, which will be referred to as IntRes2: IMM8[5:4] Description 00bPositive PolarityIntRes2 = IntRes1 01bNegative PolarityIntRes2 = -1 XOR IntRes1 10bMasked PositiveIntRes2 = IntRes1 11bMasked NegativeIntRes2 = IntRes1 if reg/mem[i] is invalid else ~IntRes1
* IMM8[6] specifies the output selection, or how IntRes2 will be processed into the output. For PCMPESTRI and PCMPISTRI, the output is an index into the data currently referenced by arg2: IMM8[6] Description 0bLeast Significant IndexECX contains the least significant set bit in IntRes2 1bMost Significant IndexECX contains the most significant set bit in IntRes2
* For PCMPESTRM and PCMPISTRM, the output is a mask reflecting all the set bits in IntRes2: IMM8[6] Description 0bLeast Significant IndexBit Mask, the least significant bits of XMM0 contain the IntRes2 16(8) bit mask. XMM0 is zero extended to 128-bits. 1bMost Significant IndexByte/Word Mask, XMM0 contains IntRes2 expanded into byte/word mask
* IMM8[7] should be set to zero since it has no designed meaning.

### The Four Instructions

PCMPISTRI, Packed Compare Implicit Length Strings, Return Index. Compares strings of implicit length and generates index in ECX.
Operands
arg1
* XMM Register
arg2
* XMM Register
* Memory
IMM8
* 8-bit Immediate value
Modified flags
* CF is reset if IntRes2 is zero, set otherwise
* ZF is set if a null terminating character is found in arg2, reset otherwise
* SF is set if a null terminating character is found in arg1, reset otherwise
* OF is set to IntRes2[0]
* AF is reset
* PF is reset
Example
Expected output:
PCMPISTRM, Packed Compare Implicit Length Strings, Return Mask. Compares strings of implicit length and generates a mask stored in XMM0.
Operands
arg1
* XMM Register
arg2
* XMM Register
* Memory
IMM8
* 8-bit Immediate value
Modified flags
* CF is reset if IntRes2 is zero, set otherwise
* ZF is set if a null terminating character is found in arg2, reset otherwise
* SF is set if a null terminating character is found in arg2, reset otherwise
* OF is set to IntRes2[0]
* AF is reset
* PF is reset
PCMPESTRI, Packed Compare Explicit Length Strings, Return Index. Compares strings of explicit length and generates index in ECX.
Operands
arg1
* XMM Register
arg2
* XMM Register
* Memory
IMM8
* 8-bit Immediate value
Implicit Operands
* EAX holds the length of arg1
* EDX holds the length of arg2
Modified flags
* CF is reset if IntRes2 is zero, set otherwise
* ZF is set if EDX is < 16(for bytes) or 8(for words), reset otherwise
* SF is set if EAX is < 16(for bytes) or 8(for words), reset otherwise
* OF is set to IntRes2[0]
* AF is reset
* PF is reset
PCMPESTRM, Packed Compare Explicit Length Strings, Return Mask. Compares strings of explicit length and generates a mask stored in XMM0.
Operands
arg1
* XMM Register
arg2
* XMM Register
* Memory
IMM8
* 8-bit Immediate value
Implicit Operands
* EAX holds the length of arg1
* EDX holds the length of arg2
Modified flags
* CF is reset if IntRes2 is zero, set otherwise
* ZF is set if EDX is < 16(for bytes) or 8(for words), reset otherwise
* SF is set if EAX is < 16(for bytes) or 8(for words), reset otherwise
* OF is set to IntRes2[0]
* AF is reset
* PF is reset

## SSE Instruction Set

There are literally hundreds of SSE instructions, some of which are capable of much more than simple SIMD arithmetic. For more in-depth references take a look at the resources chapter of this book.
You may notice that many floating point SSE instructions end with something like PS or SD. These suffixes differentiate between different versions of the operation. The first letter describes whether the instruction should be Packed or Scalar. Packed operations are applied to every member of the register, while scalar operations are applied to only the first value. For example, in pseudo-code, a packed add would be executed as:
While a scalar add would only be:
The second letter refers to the data size: either Single or Double. This simply tells the processor whether to use the register as four 32-bit floats or two 64-bit doubles, respectively.

### SSE: Added with Pentium III

Floating-point Instructions:
ADDPS, ADDSS, CMPPS, CMPSS, COMISS, CVTPI2PS, CVTPS2PI, CVTSI2SS, CVTSS2SI, CVTTPS2PI, CVTTSS2SI, DIVPS, DIVSS, LDMXCSR, MAXPS, MAXSS, MINPS, MINSS, MOVAPS, MOVHLPS, MOVHPS, MOVLHPS, MOVLPS, MOVMSKPS, MOVNTPS, MOVSS, MOVUPS, MULPS, MULSS, RCPPS, RCPSS, RSQRTPS, RSQRTSS, SHUFPS, SQRTPS, SQRTSS, STMXCSR, SUBPS, SUBSS, UCOMISS, UNPCKHPS, UNPCKLPS
Integer Instructions:
ANDNPS, ANDPS, ORPS, PAVGB, PAVGW, PEXTRW, PINSRW, PMAXSW, PMAXUB, PMINSW, PMINUB, PMOVMSKB, PMULHUW, PSADBW, PSHUFW, XORPS

### SSE2: Added with Pentium 4

Floating-point Instructions:
ADDPD, ADDSD, ANDNPD, ANDPD, CMPPD, CMPSD*, COMISD, CVTDQ2PD, CVTDQ2PS, CVTPD2DQ, CVTPD2PI, CVTPD2PS, CVTPI2PD, CVTPS2DQ, CVTPS2PD, CVTSD2SI, CVTSD2SS, CVTSI2SD, CVTSS2SD, CVTTPD2DQ, CVTTPD2PI, CVTTPS2DQ, CVTTSD2SI, DIVPD, DIVSD, MAXPD, MAXSD, MINPD, MINSD, MOVAPD, MOVHPD, MOVLPD, MOVMSKPD, MOVSD*, MOVUPD, MULPD, MULSD, ORPD, SHUFPD, SQRTPD, SQRTSD, SUBPD, SUBSD, UCOMISD, UNPCKHPD, UNPCKLPD, XORPD
    * CMPSD and MOVSD have the same name as the string instruction mnemonics CMPSD (CMPS) and MOVSD (MOVS); however, the former refer to scalar double-precision floating-points whereas the latter refer to doubleword strings.
Integer Instructions:
MOVDQ2Q, MOVDQA, MOVDQU, MOVQ2DQ, PADDQ, PSUBQ, PMULUDQ, PSHUFHW, PSHUFLW, PSHUFD, PSLLDQ, PSRLDQ, PUNPCKHQDQ, PUNPCKLQDQ

### SSE3: Added with later Pentium 4

ADDSUBPD, ADDSUBPS, HADDPD, HADDPS, HSUBPD, HSUBPS, MOVDDUP, MOVSHDUP, MOVSLDUP

### SSSE3: Added with Xeon 5100 and early Core 2

PSIGNW, PSIGND, PSIGNB, PSHUFB, PMULHRSW, PMADDUBSW, PHSUBW, PHSUBSW, PHSUBD, PHADDW, PHADDSW, PHADDD, PALIGNR, PABSW, PABSD, PABSB

### SSE4
#### SSE4.1: Added with later Core 2

MPSADBW, PHMINPOSUW, PMULLD, PMULDQ, DPPS, DPPD, BLENDPS, BLENDPD, BLENDVPS, BLENDVPD, PBLENDVB, PBLENDW, PMINSB, PMAXSB, PMINUW, PMAXUW, PMINUD, PMAXUD, PMINSD, PMAXSD, ROUNDPS, ROUNDSS, ROUNDPD, ROUNDSD, INSERTPS, PINSRB, PINSRD, PINSRQ, EXTRACTPS, PEXTRB, PEXTRW, PEXTRD, PEXTRQ, PMOVSXBW, PMOVZXBW, PMOVSXBD, PMOVZXBD, PMOVSXBQ, PMOVZXBQ, PMOVSXWD, PMOVZXWD, PMOVSXWQ, PMOVZXWQ, PMOVSXDQ, PMOVZXDQ, PTEST, PCMPEQQ, PACKUSDW, MOVNTDQA

#### SSE4a: Added with Phenom

LZCNT, POPCNT, EXTRQ, INSERTQ, MOVNTSD, MOVNTSS

#### SSE4.2: Added with Nehalem

CRC32, PCMPESTRI, PCMPESTRM, PCMPISTRI, PCMPISTRM, PCMPGTQ