SIMD为什么叫SIMD时是单条数据指令?

Why does SIMD have single data instructions when it's called SIMD?

我一直在想..它在单指令数据中被称为SIMD。那么为什么它有条数据指令呢?

例如vaddss是多条数据vaddps的单条数据等值。几乎每条 SIMD 指令都有一个数据版本。

为什么?

SIMD为什么叫SIMD时只有单条数据指令?

从这个意义上说,不是 SIMD 指令

vaddss 是一个标量 FP 数学指令,它对 FP/SIMD 寄存器 (XMM0..15) 中的数据进行运算。它存在是因为 x87 不是一个非常方便的编译器目标,它的 stack-based 寄存器通常需要 fxch 和其他怪癖。英特尔添加了一种新方法来执行标量 FP 数学以及 SSE1(浮点)和 SSE2(双精度),幸运的是这是 x86-64 的基线,所以每个人都可以使用它。

称其为 SIMD 指令的人指的是以下之一:

  • 它操作的是哪个寄存器。 (XMM0 是 16 字节宽,显然是一个 SIMD 寄存器,即使您只关心保存标量值的低位元素也是如此。)
  • 事实上,它是一条 AVX 指令,因此它与主要针对 SIMD 使用的 ISA 扩展一起引入,因此被称为 SIMD 扩展或指令集。
  • 这也意味着它使用 MXCSR 进行舍入模式和 FP 异常记录/取消屏蔽,它可以采用的异常类型与其他 SSE/AVX Intel 记录为“SIMD [=98] 的指令相同=] Exceptions”作为简明术语以区别于传统 x87。
  • 或者他们在谈论 use-case 在高元素具有实际数据时只对低元素做某事。 (非常罕见,但你可以做一些事情。也许更可能使用 sd 标量双精度,其中低双精度是 XMM 寄存器的一半。)

或者如果他们实际上是根据 Flynn's taxonomy SISD vs. SIMD vs. MIMD 等 我非常怀疑有人会不过,实际上是这个意思。 sssd 标量 FP 数学指令是 SISD,single-instruction single-data。顺便说一句,它们只存在于 FP 数学; x86 已经有像 add eax, ecx 这样的用于标量整数数学的指令,并且没有 paddb 甚至 xorps.

的标量版本

使用单独的标量 FP 数学指令的一个原因是使用 addps 也会对 XMM 寄存器的高位元素中可能存在的任何垃圾进行操作。 这会引发额外的 FP 异常(通常被屏蔽,因此仅记录在 MXCSR (fenv.h) 中,但如果未屏蔽会陷入 OS。)

上面的元素都是 0.0 (调用约定不需要,顺便说一句), addps 不会引发任何额外的异常,但是 divps 会除法零。

对于像小整数这样的 non-zero 垃圾,它可能是 bit-pattern 次正规浮点数,或者结果可能是次正规的,导致巨大的减速(~100 倍),因为 CPU 在许多情况下需要一个微代码帮助来处理次正规输入或输出(或者当 SSE1 在 Pentium III 中是新的时,可能是所有次正规情况)。除非你像 gcc -ffast-math 那样设置 FTZ 和 DAZ(刷新为零,非正规为零)。

对于像 xorpspaddq 这样不进行实际 FP 数学运算的指令,不可能有 FP 异常或微码辅助。即使您只关心 XMM 的低 32 位或 64 位,也可以只使用它们。

MMX 或 SSE2 偶尔会在 32 位代码中用于执行标量 64 位整数数学计算,高位字节为零或垃圾。 MMX paddq mm0, mm1 是 SISD 指令,但 SSE2 paddq xmm0, xmm1 是 SIMD 指令。

SSE1 是 Pentium 3 中的新功能,其中 SIMD 执行单元和寄存器只有 64 位宽。 addps 解码为 2 微指令; addss 解码为 1。因此,即使在最好的情况下,也存在性能动机。

这也可能是英特尔不幸设计的原因,其中 sqrtsscvtsi2ss 以及其他合并到目的地,需要在 xor-zeroing 上花费额外的 front-end 带宽,或者冒着虚假依赖的风险:。这是一个 short-sighted 设计决定,让它们在 Pentium 3 上 single-uop,不幸的是,他们在 SSE2 中遵循 double 精度,并在有机会时坚持使用 AVX 和 AVX-512引入具有不同语义的更好版本。至少 AVX 版本采用第二个源寄存器进行合并,因此您可以选择一个“冷”寄存器作为解决方法,请参阅我对链接副本的回答。


标量FP与SIMD共享寄存器是正常的

为标量 FP 设置另一组寄存器没有必要也没有用,与 x87 FPU 或 general-purpose 整数寄存器共享会因不同的原因而变得更糟。

SIMD 寄存器与标量 FP 寄存器重叠或相同在其他 ISA 上是完全正常的;一些没有像 x87 这样奇怪的设计的 ISA(如 ARM)不需要新的架构状态来引入 SIMD。例如ARM's NEON q0..q15 16-byte registers 映射到 VFPv3 中存在的 d0..d31 double-precision FP 寄存器对。

(不过,我不确定 partial-register 别名在其他 ISA 的 SIMD 扩展中是否真的很常见。可能是一些引入了新的架构状态,或者只是将 FP double-precision 寄存器用作 64位整数 SIMD 而不是 128位。)

在 OS 内核中,您经常谈论在上下文切换时保存“FPU 状态”(而不仅仅是 general-purpose 整数寄存器),现在 short-hand FPU 和 SIMD 状态。例如在 Linux 内核中,您需要在使用 XMM/YMM/ZMM 寄存器的 运行 指令之前使用 kernel_fpu_begin()。 (例如在 RAID5 / RAID6 驱动程序中)。