我一直在阅读最近推出的AVX-512指令,我觉得有一个我不理解的基本概念。 SIMD在已执行乱序执行的超标量CPU上有什么好处?
考虑以下伪汇编代码。使用SIMD:
load 16 floats to register simd-a
load 16 floats to register simd-b
multiply register simd-a by simd-b as 16 floats to register c
store the results to memory
这没有SIMD:
load a float to register a
load a float to register b
multiply register a and register b as floats to c
store register c to memory
load a float to register a (contiguous to prior load to a)
load a float to register b (contiguous to prior load to b)
multiply register a and register b as floats to c
store register c to memory (contiguous to previous stored result)
[continued for 16 floats]
我已经做了这样的低级工作已经有一段时间了,但在我看来,CPU可以将非SIMD示例转换为按照数据顺序运行:
从本质上讲,感觉就像CPU在两种情况下都足够智能以相同的速度运行。显然我在这里缺少一些东西,因为我们继续向ISA添加更多更宽的SIMD指令,那么这些指令的实用价值来自哪里呢?
答案 0 :(得分:5)
不同之处主要在于在硬件中实现这种设计的可行性。由于各种原因,超标量体系结构的可扩展性不是很高。例如,在一个周期中重命名那么多寄存器是很困难的,因为你重命名的东西可能是相关的(如果它真的是翻译的SIMD代码,它们不会,但你不知道)。物理寄存器文件需要一大堆额外的读写端口,这非常烦人。相比之下,更宽泛的寄存器很容易。转发网络的规模会爆炸。每个周期都必须将批次的μops插入到活动窗口中,其中很多都必须被唤醒和发送,并且其中很多都必须退出。由于机器现在被淹没了一个数量级更多的μops,你可能想要支持更大的活动窗口,否则它实际上变得更小(对于相同的代码它变得不那么有效)。
整个内存业务也更难,因为现在你必须支持一个周期中的大量访问(所有访问都必须通过单独的翻译,对它们应用排序约束,参与转发等等) ),而不仅仅是更广泛的访问(相对容易)。
基本上这个假设设计需要很多很难用合理的功率和面积预算有效实现的东西,然后使它们变得更加困难。许多事物的复杂性与你想要在一个周期中通过它们的μop数量大致成二次方式,而不是线性地。
添加更宽的SIMD,他们一直在做的方式,主要是复制粘贴SIMD单元(因此大多数AVX和AVX2指令的令人讨厌的语义)并给出一些更高的位宽。如果你这样做,就没有糟糕的缩放。