Assembly 128位到512位寄存器的用途是什么?

Assembly 128位到512位寄存器的用途是什么?,assembly,x86-64,sse,simd,cpu-registers,Assembly,X86 64,Sse,Simd,Cpu Registers,在查看了x86/x64体系结构中的寄存器表之后,我注意到有一整段128、256和512位寄存器,我从未见过它们被用于汇编或反编译的C/C++代码:XMM(0-15)代表128,YMM(0-15)代表256,ZMM(0-31)512 在做了一些挖掘之后,我收集到的是,为了对128位数字执行数学运算,必须使用2个64位运算,而不是使用泛型的add,sub,mul,div运算。如果是这种情况,那么拥有这些扩展寄存器集的具体用途是什么?您是否可以使用任何汇编操作来操作它们?这些寄存器是SSE、AVX和A

在查看了x86/x64体系结构中的寄存器表之后,我注意到有一整段128、256和512位寄存器,我从未见过它们被用于汇编或反编译的C/C++代码:XMM(0-15)代表128,YMM(0-15)代表256,ZMM(0-31)512


在做了一些挖掘之后,我收集到的是,为了对128位数字执行数学运算,必须使用2个64位运算,而不是使用泛型的
add
sub
mul
div
运算。如果是这种情况,那么拥有这些扩展寄存器集的具体用途是什么?您是否可以使用任何汇编操作来操作它们?

这些寄存器是SSE、AVX和AVX512指令集扩展的一部分。您的C编译器应该至少将它们中较低的64位用于ABI中指定的浮点操作

这些寄存器是SIMD(单指令多数据)寄存器,主要用于高性能代码。处理器支持特殊的SIMD指令,可同时处理多个数据,处理单个数据所需的时间与通常所需的时间相同。大多数使用这些寄存器的代码都是在汇编程序中编写的,或者使用特殊的内在函数,因为编译器不善于单独使用SIMD指令。使编译器在这方面做得更好(一种称为自动矢量化的优化)是一个活跃的研究领域

例如,假设一个程序要对双精度浮点数进行矩阵乘法。使用AVX寄存器ymm0到ymm15,一次可以处理4个数字,与正常实现相比,算法速度提高了4倍。那是相当不同的

有关使用这些寄存器的指令,请参阅指令集参考。以可访问的方式列出所有这些选项。如果您想使用它们,我建议您使用内部函数,因为它们比汇编更易于使用。

这些函数在

  • 浮点运算
  • 一次对多个数据执行操作
必须使用2个64位操作才能对128位数字执行数学运算

不,它们不是为了这个目的,你不能轻易地将它们用于128位数字。仅用2条指令添加128位的数字要快得多:如果处理XMM寄存器,则不需要大量指令。看


关于它们的用法,首先它们用于标量浮点操作。因此,如果在C或C++中有<代码>浮点<代码>或<代码>双< /代码>,那么它们很可能被存储在XMM寄存器的低端,并由在<代码> SS <代码>(标量单)或<代码> SD(标量双)

中的指令操作。 事实上,还有另外一组80位
ST(x)
寄存器,可用于进行浮点运算。然而,它们很慢,而且不太可预测。速度慢,因为默认情况下操作的精度更高,这本身就需要更多的工作,必要时也需要更多的工作。不可预测也是因为高精度。这一点一开始可能会感到奇怪,但很容易解释,例如,某些操作在
float
double
精度中溢出或下溢,但在
long double
精度中则不然。这会在32位和64位build1中导致许多错误或意外结果

转向更快、更一致的SSE寄存器是原因之一


然后英特尔推出了for操作,它使用相同的
ST(x)
寄存器,并使用新名称
MMX
。MMX可能代表多重数学扩展或矩阵数学扩展,但IMHO最有可能是多媒体扩展,因为多媒体和互联网在当时变得越来越重要。在多媒体解决方案中,您通常必须对每个像素、纹理、声音样本执行相同的操作。。。像这样

for (int i = 0; i < 100000; ++i)
{
   A[i] = B[i] + C[i];
   D[i] = E[i] * F[i];
}
for(int i=0;i<100000;++i)
{
A[i]=B[i]+C[i];
D[i]=E[i]*F[i];
}
我们可以通过一次执行多个元素来提高速度,而不是单独对每个元素进行操作。这就是人们发明SIMD的原因。使用MMX,您可以同时增加8个像素通道的亮度,或四个16位声音采样的音量。。。调用单个元素上的操作,完整寄存器称为向量,向量是一组标量值

由于MMX的缺点(如重复使用
ST
寄存器,或缺乏浮点支持),在使用Intel扩展SIMD指令集时,决定为它们提供一组全新的寄存器,名为XMM,其长度为两倍(128位),因此现在我们可以一次操作16字节。它还支持同时执行多个浮点操作。然后Intel在中将XMM延长到256位YMM,并在中再次将长度增加了一倍(这一次它还将64位模式下的寄存器数量增加到32个)。现在您可以一次处理16个32位整数

通过以上内容,您可能了解了这些寄存器的第二个也是最重要的作用:使用一条指令并行地对多个数据执行操作。例如,在一组已介绍的。现在您可以计算字符串长度,查找子字符串。。。一次检查多个字节的速度要快得多。您还可以更快地复制或比较内存。现代
memcpy
实现根据最大寄存器宽度一次移动16、32或64字节,而不是像最简单的C解决方案那样逐个移动

不幸的是,编译器在将标量代码转换为并行代码方面仍然很差,因此大多数时候我们必须帮助他们,尽管自动矢量化仍然在变得更好、更智能

  • for (int i = 0; i < 100000; ++i) { A[i] = B[i] + C[i]; D[i] = E[i] * F[i]; }