在查看x86/x64架构中的寄存器表之后,我注意到有128,256和512位寄存器的整个部分,我从未见过它们用于汇编或反编译的C/C++代码: XMM(0-15)表示128,YMM(0-15)表示256,ZMM(0-31)512.
做了一些挖后我所收集的是,你必须使用2个64位操作,以一个128位的数字进行的,而不是使用通用的数学,add
,sub
,mul
,div
操作.如果是这种情况,那么具有这些扩展寄存器集的用途究竟是什么,是否有任何汇编操作可以用来操作它们?
1> phuclv..:
那些用于
浮点运算
一次对多个数据进行操作
您必须使用2个64位操作才能在128位数上执行数学运算
不,它们不是为了这个目的,你不能轻易地将它们用于128位数字.使用仅2条指令添加128位数字要快得多:add rax, rbx; adc rdx, rcx
如果处理XMM寄存器,则代替大量指令.看到
实用的BigNum AVX/SSE可能吗?
是否可以使用SSE(v2)来生成128位宽的整数?
关于它们的用法,首先它们用于标量浮点运算.所以,如果你有float
或double
C或C++那么他们最有可能被存储在XMM寄存器的低位部分和操纵在结束指令ss
(标量单)或sd
(标双)
事实上,还有另外一组8个80位ST(x)
寄存器可用于x87协处理器,用于进行浮点数学运算.然而,它们很慢而且不太可预测.慢,因为默认情况下操作以更高的精度完成,这本身就需要更多的工作,并且还需要存储然后加载以在必要时舍入到更低的精度.不可预测也是因为精度高.起初可能会感到奇怪,但很容易解释,例如某些操作溢出或下溢float
或double
精确,但long double
不精确.这会在32位和64位构建1中导致许多错误或意外结果
这是两组寄存器的浮点示例
// 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寄存器的迁移是MSVC中不再提供80位扩展精度类型的原因之一long double
然后,英特尔为SIMD操作引入了MMX指令集,该指令集使用与新名称相同的寄存器.MMX可能代表多数学扩展或矩阵数学扩展,但恕我直言,它最有可能或多媒体扩展,因为多媒体和互联网在当时越来越重要.在多媒体解决方案中,您经常需要对每个像素,纹素,声音样本执行相同的操作......就像这些一样ST(x)
MMX
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
寄存器的重用或缺乏浮点支持),当扩展SIMD指令集与流式SIMD扩展(SSE)时,英特尔决定给它们一组全新的名为XMM 的寄存器,这是两次更长(128位),所以现在我们可以一次操作16个字节.它还支持一次多个浮点运算.然后英特尔将XMM延长到高级矢量扩展(AVX)中的256位YMM ,并在AVX-512中再次将长度加倍(这次它在64位模式下也将寄存器数量增加到32).现在,您可以在工作16个32位整数,在一个时间
从上面您可以理解这些寄存器的第二个也是最重要的作用:使用单个指令并行处理多个数据.例如,在SSE4中,引入了一组处理C字符串的指令.现在你可以通过一次检查多个字节来计算字符串长度,查找子字符串...更快.您还可以更快地复制或比较内存.现代memcpy
实现一次移动16个,32个或64个字节,具体取决于最大的寄存器宽度,而不是像最简单的C解决方案那样逐个移动.
不幸的是,编译器仍然不善于将标量代码转换为并行代码,因此大多数时候我们必须帮助它们,尽管自动矢量化仍然变得更好更智能
自动矢量化
自动并行化和自动矢量化
由于SIMD的重要性,现在几乎所有高性能架构都有自己的SIMD版本,如PowerPC 上的Altivec或ARM 上的Neon.
1一些例子:
SSE浮点运算是否可重复?
x87中的扩展(80位)双浮点,而不是SSE2 - 我们不会错过它?
acos(double)在x64和x32 Visual Studio上给出不同的结果
为什么相同的代码会在32位与64位计算机上产生不同的数字结果?
x86和x64之间的浮点算术的差异
std :: pow在32位和64位应用程序中产生不同的结果
为什么Math.Exp在32位和64位之间给出不同的结果,具有相同的输入,相同的硬件