assembly - 128位至512位寄存器有什么用?

标签 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。

在做了一点挖掘之后,我必须使用2个64位运算来对128位数字进行数学运算,而不是使用通用的addsubmuldiv运算。如果是这种情况,那么拥有这些扩展的寄存器集到底有什么用,并且可以使用任何汇编操作来对其进行操作?

最佳答案

这些用于

  • 浮点运算
  • 一次对多个数据进行操作

  • you have to use 2 64 bit operations in order to perform math on a 128 bit number



    不,它们不是用于此目的的,您不能轻松地将它们用于128位数字。仅用2条指令添加128位数字的速度要快得多:如果处理XMM寄存器,则使用 add rax, rbx; adc rdx, rcx 而不是大量指令。看
  • practical BigNum AVX/SSE possible?
  • Is it possible to use SSE (v2) to make a 128-bit wide integer?


  • 关于它们的用法,首先将它们用于标量浮点运算。因此,如果您在C或C++中具有floatdouble,则很可能将它们存储在XMM寄存器的下部,并通过以ss(标量单)或sd(标量双)结尾的指令进行操作

    实际上,还有另一组八个80位ST(x)寄存器,可与x87 co-processor一起使用来进行浮点数学运算。但是,它们速度慢且难以预测。速度慢,因为默认情况下操作会以更高的精度进行,这固有地需要更多的工作,并且在必要时还需要requires a store then load to round to lower precision。高精度也是不可预测的。乍一看这很奇怪,但是很容易解释,例如某些操作在floatdouble精度上上溢或下溢,但在long double精度上不上。这会导致32和64位build1中的许多错误或意外结果

    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的原因之一

    然后,英特尔为MMX instruction set操作引入了SIMD,该操作使用具有新名称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个像素 channel 的亮度,或者一次增加四个16位声音样本的音量...单个元素上的操作称为scalar,完整寄存器称为矢量,它是一组标量值(value)观

    由于MMX的缺点(例如重用ST寄存器或缺少浮点支持),当使用Streaming SIMD Extensions (SSE)扩展SIMD指令集时,英特尔决定为它们提供一套全新的名为XMM的寄存器,该寄存器集的长度是原来的两倍(128位) ),因此我们现在可以一次处理16个字节。而且它还一次支持多个浮点运算。然后,Intel在Advanced Vector Extensions (AVX)中将XMM扩展为256位YMM,并在AVX-512中将其长度再次加倍(这也使寄存器的数量在64位模式下增加到32个)。现在您可以一次处理十六个32位整数

    通过上面的内容,您可能会了解这些寄存器的第二个也是最重要的角色:与单个指令并行执行多个数据的操作。例如,在SSE4中引入了一组instructions to work on C strings。现在您可以计算字符串长度,查找子字符串...通过一次检查多个字节来更快。您还可以更快地复制或比较内存。现代memcpy实现一次最多可移动16、32或64个字节,具体取决于最大的寄存器宽度,而不是像最简单的C解决方案那样一一对应。

    不幸的是,尽管自动矢量化仍在变得越来越智能,但编译器仍然无法从标量代码转换为并行代码,因此大多数时候我们都必须提供帮助。
  • Automatic vectorization
  • Auto-Parallelization and Auto-Vectorization

  • 由于SIMD的重要性,当今几乎所有高性能架构都具有自己的SIMD版本,例如PowerPC上的Altivec或ARM上的Neon

    1一些例子:
  • Is SSE floating-point arithmetic reproducible?
  • Extended (80-bit) double floating point in x87, not SSE2 - we don't miss it?
  • acos(double) gives different result on x64 and x32 Visual Studio
  • Why would the same code yield different numeric results on 32 vs 64-bit machines?
  • Difference in floating point arithmetics between x86 and x64
  • std::pow produce different result in 32 bit and 64 bit application
  • Why does Math.Exp give different results between 32-bit and 64-bit, with same input, same hardware
  • 关于assembly - 128位至512位寄存器有什么用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52932539/

    相关文章:

    assembly - Commodore 64 平滑滚动条位于第 1 行 - 如果在第 0 行设置了中断,则会在屏幕上跳跃

    c - 将指针作为局部变量的函数的汇编指令

    linux - 递归删除 x64 程序集中的文件

    c++ - SSE 半负载 (_mm_loadh_pi/_mm_loadl_pi) 发出警告

    c - 执行 x87 FPATAN 操作的扩展 GCC 内联汇编中的 clobber 列表的说明

    assembly - CUDA有汇编语言吗?

    assembly - 如何使用汇编语言中的键结束程序

    c - 获取__data_start符号的地址

    x86 - 对齐与未对齐 x86 SIMD 指令之间的选择

    c++ - 同时使用多个 SIMD 指令集的好处