有 32 个浮点标量寄存器有用吗?

Is it useful to have 32 floating-point scalar registers?

在指令集架构的设计中,16个整数寄存器已经接近递减点returns;如果您为 16 和 32 寄存器编译典型代码并保持其他一切不变,溢出的数量只会非常轻微地减少(然后对于 64 寄存器则根本不会减少)。

但是,我看到它声称您确实确实需要至少 32 个浮点寄存器,而普通算法确实有明显超过 16 个浮点寄存器。

是不是因为人们经常处理一种或另一种形式的浮点向量,所以如果将它们解压缩成这样,它们将占用许多标量寄存器?或者即使您还有一组向量寄存器,您仍然想要 32 个浮点标量寄存器吗?

不,如果您要矢量化,那么您有时会希望使用超过 16 个 FP 向量。这绝对与将向量解包为标量无关。

通常您需要大量 regs 来展开多个累加器以隐藏 FP 延迟,因为 FP 通常具有比整数 SIMD 更高的延迟指令。 ( 有一节介绍此内容。)

And/or 用于在有限范围内为 explog 等函数的多项式逼近保存一组系数。同样,FP SIMD 比整数 SIMD 更有可能使用大量寄存器;例如,整数代码可能需要一些 AND 掩码和洗牌控制常量,但通常没有 FP 那么多。对于您为矢量化 log() 函数划分的几个多项式,使用 5 个系数的 FP 代码并不少见。如果将其内联到一个循环中以便这些常量可以保留在 regs 中,那么当您有一些用于加载和存储数据的暂存 regs 时,您很容易超过 16 个寄存器,特别是如果您正在计算 包含 log() 还有其他东西。

我在 上的回答也 一些 提到了这一点,但它绝对不是重复的。 (该问题的主旨与此不同:GP 整数与 SIMD(包括标量 FP)共享相同的寄存器 space,而不是将标量 FP 与向量 FP 分开。)

Or would you still want 32 floating-point scalar registers, even if you also had a set of vector registers?

呃...普通 ISA 在用于 SIMD 向量的相同寄存器中进行标量数学运算。所以这个问题很少出现。

我倾向于说不,除非您不能将矢量寄存器用于标量 FP,或者您的矢量寄存器要少得多。 32 个架构寄存器通常就足够了,尤其是将寄存器重命名为更大的物理寄存器文件以隐藏跨迭代独立使用同一架构寄存器的延迟。 save/restore 的状态越多,上下文切换的成本就越高,而使用这些标量寄存器而不是向量寄存器的另一组操作码也将是一种机会成本(取消操作码编码 space 可能会允许未来扩展名)。

32-bit ARM (with NEON) makes an interesting tradeoff: d0..d31 (64-bit double-precision FP registers) which can be used for 64-bit SIMD 或标量 FP,以及 16x 128 位 q 寄存器的别名(共享 space)。 (NEON registers) 不幸的是,访问 q 寄存器的 2 d 部分对于寄存器重命名是不方便的,就像 x86 的部分寄存器问题一样。 (我通过不提及 32x 32 位 s regs 来简化,这些 regs 是低 16 d regs 的别名,可用于标量单精度。)

AArch64 将其简化为 32 个 128 位 q 寄存器,每个寄存器的低半部分是相同编号的 d 寄存器(而不是 2n 和 2n+1)。在 AArch64.

中,没有寄存器名称为 q reg 的上半部分起别名

对于 x86,AVX512 扩展扩展到 32 个矢量寄存器(从带有 SSE2 或 AVX 的 x86-64 中的 16 个)并将它们扩展到 512 位。 AVX-512 最初是为类似 GPU 的有序处理器 (Larrabee1) 设计的,因此隐藏延迟的软件流水线至关重要,因为寄存器重命名无济于事.如果不是为了那个最初的目标,我不知道英特尔是否会添加更多的寄存器。如果它全部在使用中(并且不知道为零,这可能会让 xsaveopt 指令优化保存),那么在上下文切换时它确实相当于 save/restore 的大量架构状态。

脚注 1:Larrabee 最终演变成 Xeon Phi 计算卡。