这些用于
现在它们也常用于
- 海量数据移动(如
memcpy),因为它们可以在迭代中复制大量数据:
- 字符串操作(避免逐个字符迭代):
您必须使用 2 个 64 位运算才能对 128 位数字执行数学运算
不,它们不是为此目的而设计的,您不能轻易地将它们用于 128 位数字。添加一个只有 2 条指令的 128 位数字要快得多:add rax, rbx; adc rdx, rcx,而不是处理 XMM 寄存器时的大量指令。见
关于它们的用法,首先它们用于标量浮点运算。因此,如果您在 C 或 C++ 中有 float 或 double,那么它们很可能存储在 XMM 寄存器的低位,并由以 ss 结尾的指令进行操作(标量单)或sd (双精度标量)
事实上,还有一组 8 个 80 位 ST(x) 寄存器可用于 x87 co-processor 进行浮点数学运算。然而,它们速度慢且难以预测。慢,因为默认情况下操作以更高的精度完成,这本质上需要更多的工作,如果需要,还需要requires a store then load to round to lower precision。不可预知也是因为精度高。起初可能会觉得奇怪,但很容易解释,例如 float 或 double 精度中的某些操作溢出或下溢,但 long double 精度中没有。这会在 32 位和 64 位版本中导致许多错误或意外结果1
Here is a floating-point example on both sets of registers
// f = x/z + y*z
x87:
fld dword ptr [esp + 12]
fld st(0)
fdivr dword ptr [esp + 4]
fxch st(1)
fmul dword ptr [esp + 8]
faddp st(1)
ret
SSE:
divss xmm0, xmm2
mulss xmm1, xmm2
addss xmm0, xmm1
ret
AVX:
vdivss xmm0, xmm0, xmm2
vmulss xmm1, xmm1, xmm2
vaddss xmm0, xmm0, xmm1
ret
转向更快、更一致的 SSE 寄存器是the 80-bit extended precision long double type is not available in MSVC anymore 的原因之一
然后英特尔为SIMD 操作引入了MMX instruction set,它使用相同的ST(x) 寄存器和新名称MMX。 MMX 可能代表 Multiple Math eXtension 或 Matrix Math eXtension,但恕我直言,它最有可能代表 MultiMedia eXtension,因为多媒体和互联网变得越来越重要当时。在多媒体解决方案中,您经常需要对每个像素、纹素、声音样本......像这些
for (int i = 0; i < 100000; ++i)
{
A[i] = B[i] + C[i];
D[i] = E[i] * F[i];
}
我们可以通过一次处理多个元素来加快速度,而不是单独对每个元素进行操作。这就是人们发明 SIMD 的原因。使用 MMX,您可以一次增加 8 个像素通道的亮度,或四个 16 位声音样本的音量...对单个元素的操作称为scalar,而完整的寄存器称为向量,它是一个集合标量值
由于 MMX 的缺点(例如重复使用 ST 寄存器,或缺乏浮点支持),当使用 Streaming SIMD Extensions (SSE) 扩展 SIMD 指令集时,英特尔决定为它们提供一套全新的名为 XMM 的寄存器 长了两倍(128 位),所以现在我们可以一次对 16 个字节进行操作。它还同时支持多个浮点运算。然后 Intel 在Advanced Vector Extensions (AVX) 中将 XMM 加长为 256 位 YMM,并在 AVX-512 中再次将长度加倍(这一次它还在 64 位模式下将寄存器数量增加到了 32 个)。现在您可以一次处理16 个 32 位整数
从上面你可能会理解这些寄存器的第二个也是最重要的作用:用一条指令并行地对多个数据进行操作。例如在SSE4 中引入了一组instructions to work on C strings。现在您可以通过一次检查多个字节来计算字符串长度、查找子字符串...更快。您还可以更快地复制或比较内存。现代的memcpy 实现一次移动 16、32 或 64 个字节,具体取决于最大的寄存器宽度,而不是像最简单的 C 解决方案那样一个接一个地移动。
不幸的是,编译器在将标量代码转换为并行代码方面仍然很糟糕,所以大多数时候我们不得不帮助他们,尽管自动矢量化仍然变得更好和更智能
由于 SIMD 的重要性,现在几乎所有高性能架构都有自己的 SIMD 版本,例如 PowerPC 上的 Altivec 或 ARM 上的 Neon/SVE。
1一些例子: