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



对于 64 位 x86 寄存器,如果一个值的大小足够小,以至于多个指令可以放入一个寄存器中,是否可以在同一寄存器中一次保存多个值?例如,将两个 32 位整数放入一个寄存器中。如果可能的话,这是一件坏事吗?我一直在阅读寄存器,我对这个概念很陌生。

寄存器不保存指令,但我假设你的意思是将多个放入一个寄存器中,以便你可以用一条指令将它们相加。


是的,这称为 SIMD。 (单指令,多数据)在 x86-64 上,SSE2(SIMD 流指令扩展)保证可用,因此您有 16 个不同的 16 字节寄存器 (xmm0..15). 并且您有指令可以对字节、字、dword 和 qword 操作数大小执行 4x 32 位浮点数、2x 64 位双精度、

打包整数添加/子/cmp/shift/等的打包 FP 添加/子/mul/div/sqrt/cmp/cmp。(有一些差距;SSE2 不是很正交,例如最窄的移位是 16 位,打包最小/最大仅适用于某些大小。 SSE4.1填补了其中一些空白)。

以及元素宽度无关紧要的按位布尔内容(直到带有掩码寄存器的 AVX512 ......

请参阅 https://www.felixcloutier.com/x86/。p...指令(如paddw)是打包整数。...pspd是浮点打包单或打包双。

编译器经常使用 SSE/SSE2 指令,例如movdqa零或复制 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;
}

在 Godbolt 编译器资源管理器上使用 GCC9.3 -O3 for x86-64 进行这样的编译

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 位累加器中。

如何在 32 位整数中计算设置位数中显示的 popcnt bithack?,扩大到 4 位计数器,然后扩大到 8 位,然后使用乘法移位并加以 4 个不同的移位并产生高字节中的总和。

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

但是,如果您想将指令存储为数据,我相信(从这里开始)最长的 x86 指令约为 15 个字节或 120 位。所以,不,它不适合单个 64 位寄存器。

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

即使没有这个,你当然也可以通过使用按位运算(如andornotxor)和位移运算(如shlshrrolror)将"子寄存器"插入/提取到寄存器中/从寄存器中提取。

相关内容

  • 没有找到相关文章

最新更新