SSE Instructions

SSE Instructions

记录一些 SSE 指令集最基础的东西,经常容易忘。

一些比较混的概念 SSE、MMX、XMM、SIMD

SIMD: Single instruction, multiple data 就是一条指令处理一组数据,描述指令集性质的一个缩写。

SSE 是 SIMD 指令集,支持同时处理多组数据(整数/浮点),属于 SIMD 指令集。 SSE 进一步升级还有SSE2,SSE3……

MMX 也是 SIMD 指令集,只不过是以前 IA32 的 SIMD 解决方案,缺点是占用 FPU 寄存器,浮点和 SIMD 不能同时处理,SSE 引入了 XMM 寄存器解决了这个问题。

SIMD 指令集主要用于多媒体操作吧,比如信号/图像处理,这些处理涉及到大量的矩阵运算。简单说,矩阵基本运算用 for 循环实现真的太拉垮。一般线性代数库就会用平台 SIMD 指令集优化计算算法,这也是为什么 ml 里面的各种公式最好要向量化实现。

寄存器

SSE 最基本的寄存器: XMM0 - XMM7: 128 bit registers

AMD64 (x86-64) / IA64: XMM8 - XMM15

SSE 指令

指令速查网站:https://software.intel.com/sites/landingpage/IntrinsicsGuide/

本文记录的指令有SSE,SSE2,SSE3

SSE 指令运算有两种类型 packedscalar

packed 多组数据一起运算

scalar 只有一组数据运算(标量运算)(低64/32位)

Floating-point instructions

内存 Load / Store

  • Scalar – MOVSS
  • Packed – MOVAPS, MOVUPS, MOVLPS, MOVHPS, MOVLHPS, MOVHLPS, MOVMSKPS
  • MOVAPS,MOVUPS
    • 区别:前者要求内存地址 16 字节对齐,后者不需要对齐。
    • 共同:Load 完整 128 bit
  • movhps - to/from the higher part of xmm register.
  • movlps - to/from the lower part of xmm.
  • movhlps - from higher part of source register to lower part of destination register.
  • movlhps - from lower part of source register to higher part of destination register.

运算

  • Scalar – ADDSS, SUBSS, MULSS, DIVSS, RCPSS, SQRTSS, MAXSS, MINSS, RSQRTSS
  • Packed – ADDPS, SUBPS, MULPS, DIVPS, RCPPS, SQRTPS, MAXPS, MINPS, RSQRTPS

比较

  • Scalar – CMPSS, COMISS, UCOMISS
  • Packed – CMPPS

数据改组(shuffle/unpacking)

  • Packed – SHUFPS, UNPCKHPS, UNPCKLPS

shuffle 机翻译出来就是改组,我也不知道翻译对不对。shuffle 将 XMM 寄存器中元素的顺序改变或者混和两个寄存器的值。

shufps 指令有 3 个操作数(2个XMM寄存器,8bit的掩码)

1
shufps xmm, xmm, imm8

目的寄存器的前两个元素(低64bit)可以被覆盖成目的寄存器的任意两个元素。

目的寄存器的第三四元素(高32bit)可以被源寄存器任意两个元素。

imm8 掩码作用是控制元素的选择,掩码分成 4 组长度为2bit的数据 00 | 00 | 00 | 00,分别控制元素来源的选择。

00 - src[31:0]

01 - src[63:32]

10 - src[95:64]

11 - src[127:96]

src 可以是目的寄存器和源寄存器, 取决于目的寄存器中重组的位置。

intel 给的伪代码很清晰

1
2
3
4
5
6
7
8
9
10
11
12
13
DEFINE SELECT4(src, control) {
CASE(control[1:0]) OF
0: tmp[31:0] := src[31:0]
1: tmp[31:0] := src[63:32]
2: tmp[31:0] := src[95:64]
3: tmp[31:0] := src[127:96]
ESAC
RETURN tmp[31:0]
}
dst[31:0] := SELECT4(a[127:0], imm8[1:0])
dst[63:32] := SELECT4(a[127:0], imm8[3:2])
dst[95:64] := SELECT4(b[127:0], imm8[5:4])
dst[127:96] := SELECT4(b[127:0], imm8[7:6])

数据类型转换

整数转浮点,浮点转整数

  • Scalar – CVTSI2SS, CVTSS2SI, CVTTSS2SI, cvtsi2sd,cvtsd2si,cvttsd2si
  • Packed – CVTPI2PS, CVTPS2PI, CVTTPS2PI
  • Integer to float/doubles
    • cvtsi2ss, cvtsi2sd
  • floats/doubles to integers
    • cvtss2si convert 32-bit float to integer, round up/down
    • cvttss2si convert 32-bit float to integer, truncate result
    • cvtsd2si convert 64-bit double to integer, round
    • cvttsd2si convert 64-bit double to integer, truncate
  • Convert between floats and doubles

    • cvtss2sd convert 32-bit float to 64-bit double
    • cvtsd2ss convert 64-bit float to 32-bit float

先说一下命名,例如 CVTSI2SS

CVT + SI + 2 + SS:

  • SI: Scalar Integer
  • SS: Scalar Single Folat point
  • 整数转单精度浮点

CVTSS2SI CVT + SS + 2 + SI 即单精度浮点转整数

CVTTSS2SI CVTT + SS + 2 + SI 也是单精度浮点转整数 (Truncation)

总结一下:

  • SS: 标量,单精度浮点
  • SI: 标量,整数
  • SD: 标量,双精度浮点
  • PS: 向量,单精度浮点
  • PI:向量,整数
  • PD: 向量,双精度
  • US: unisgned 无符号

cvtcvtt 有什么区别呢?

cvt 转换浮点时就近舍去浮点(四舍五入),cvtt 直接舍掉小数点后的数字保留整数部分(c/c++ 默认)

CVTPI2PS CVT + PI + 2 + PS:

  • PI: Packed Integer
  • PS: packed Single Float

逻辑运算

  • Packed – ANDPS, ORPS, XORPS, ANDNPS

ANDPS: AND + Packed + Single

Integer instructions

Arithmetic

  • PADDB, PADDW, PADDD,PADDQ, PADDSBPADDSB
  • PMULHUW, PSADBW, PAVGB, PAVGW, PMAXUB, PMINUB, PMAXSW, PMINSW

PADDSB :Add packed signed byte integers with saturation

saturation 是运算比较特殊运行,可以运算将结果限制在某个区间内。

Data movement

  • PEXTRW, PINSRW

Other

  • PMOVMSKB, PSHUFW

参考

[1] https://en.wikipedia.org/wiki/Streaming_SIMD_Extensions “Streaming SIMD Extensions”

[2] https://blog.csdn.net/arau_sh/article/details/6161871 “MMX 和SSE指令集的区别是什么”

[3] https://stackoverflow.com/questions/16218665/simd-and-difference-between-packed-and-scalar-double-precision “SIMD and difference between packed and scalar double precision”

[4] https://students.mimuw.edu.pl/~zbyszek/asm/en/instrukcje-sse.html “SSE Instructions (Streaming SIMD Extensions)”

[5] https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_shuffle_ps&expand=5197 “Intrinsics Guide”

[6] https://blog.csdn.net/zp288105109a/article/details/100008264 “[汇编]汇编学习笔记(4):SHUFPS(洗牌)指令”

[6] https://www.cs.uaf.edu/2012/fall/cs301/lecture/10_26_asm_float.html “CS301: Floating Point in x86 Assembly”

[7] https://montcs.bloomu.edu/Presentations/Old/240/16.floating-point-SSE.pdf “Introduction to Scalar FloatingPoint Operations via SSE”

[8] https://en.wikipedia.org/wiki/X86_instruction_listings#SSE2_instructions “x86 instruction listings”


本博客所有文章除特别声明外,均采用 CC BY-SA 4.0 协议 ,转载请注明出处!