寄存器一次可以保存多个值吗?

时间:2020-04-11 23:46:11

标签: assembly x86-64 simd cpu-registers swar

对于64位x86寄存器,如果一个值的大小足够小,使得一个寄存器可以容纳多个指令,那么是否可以一次在一个寄存器中保存多个值?例如,将两个32位int装入一个寄存器。如果可能的话,这将是一件坏事吗?我一直在阅读寄存器,并且对这个概念还很陌生。

2 个答案:

答案 0 :(得分:3)

寄存器不保存指令,但我假设您的意思是将多个装入一个寄存器,以便您可以用一条指令将它们都添加。


是的,这称为SIMD. (Single Instruction, Multiple Data) 。在x86-64上,保证SSE2(流式SIMD扩展名)可用,因此您有16个不同的16字节寄存器(xmm0。 15)。而且您有说明可以对字节,字,dword进行打包的FP add / sub / mul / div / sqrt / cmp 4x 32位浮点数,2x 64位double,打包整数add / sub / cmp / shift / etc和qword操作数大小。

(存在一些间隙; SSE2不是非常正交的,例如,最窄的移位是16位,压缩的最小/最大仅适用于某些大小。其中一些间隙由SSE4.1填充)。

与元素宽度无关的按位布尔运算(直到带掩码寄存器的AVX512 ...)

请参见https://www.felixcloutier.com/x86/p...之类的paddw条指令是打包整数。 ...pspd是浮点压缩单或压缩双。

编译器经常使用movdqa之类的SSE / SSE2指令将内存清零或以16字节块的形式复制,以及“向量化”(使用SIMD计算)以进行数组循环。例如,GCC 7或8以及以后的版本知道如何使用RAX将相邻结构成员或数组元素的加载/存储合并为标量加载或存储。

例如数组的总和:

int sumarr(const int *arr)
{
    int sum = 0;
    for(int i=0; i < 10240; i++) {
        sum += arr[i];
    }
    return sum;
}

使用xcc-64 on the Godbolt compiler explorer的GCC9.3 -O3进行这样的编译

sumarr:
        lea     rax, [rdi+40960]            # endp = arr + size
        pxor    xmm0, xmm0
.L2:                                        # do {
        movdqu  xmm2, XMMWORD PTR [rdi]        # v = arr[i + 0..3]
        add     rdi, 16                        # p += 4
        paddd   xmm0, xmm2                     # sum += v  // packed addition of 4 elements
        cmp     rax, rdi
        jne     .L2                         # }while(p != endp)
   ... then a horizontal vector sum ...
        MOVD eax, xmm0
        ret

矢量化有点像并行化,对于这种简化(将数组求和为标量),需要关联操作。例如FP版本只能使用-ffast-math或OpenMP进行矢量化。


在像RAX这样的通用寄存器中,没有指令进行SIMD加法而不在字节边界之间进位(就像paddb xmm0, xmm1这样),它被称为SWAR(寄存器中的SIMD)。

过去,这种技术在没有适当的SIMD指令集(如Alpha或MIPS64)的ISA上更有用。但这仍然是可能的,SWAR技术可以在没有popcnt指令(例如,掩盖每隔一位并进行移位,这样您就可以有效地将32个独立的加法(不会互相溢出)加到2位累加器中。

How to count the number of set bits in a 32-bit integer?中显示的popcnt bithack做到了这一点,将其扩宽为4位计数器,然后扩展为8位,然后使用乘法进行4次不同的移位加法运算,并在高字节中产生总和。

答案 1 :(得分:2)

寄存器不倾向于保存指令,而是保存要由指令处理的数据。

但是,如果您想要将指令存储为数据,我相信(来自here),最长的x86指令大约为15个字节或120位。因此,不,它不能放入单个64位寄存器中。

就在单个寄存器中保存多个数据值而言,这肯定是可能的。甚至硬件也支持此功能,即使是最早的x86芯片也具有ahal,它们共同构成了ax寄存器。

即使没有这些,您当然也可以通过使用按位运算(例如andornot和{{ 1}})和位移操作(如xorshlshrrol)。

相关问题