考虑 LLVM MCA 文档中的以下说明
vmulps %xmm0, %xmm1, %xmm2
vhaddps %xmm2, %xmm2, %xmm3
vhaddps %xmm3, %xmm3, %xmm4
文档包含关于 3 次迭代的模拟循环中指令状态转换的精彩讨论。根据文档,状态转换是:
[0,0] DeeER. . . vmulps %xmm0, %xmm1, %xmm2
[0,1] D==eeeER . . vhaddps %xmm2, %xmm2, %xmm3
[0,2] .D====eeeER . vhaddps %xmm3, %xmm3, %xmm4
[1,0] .DeeE-----R . vmulps %xmm0, %xmm1, %xmm2
[1,1] . D=eeeE---R . vhaddps %xmm2, %xmm2, %xmm3
[1,2] . D====eeeER . vhaddps %xmm3, %xmm3, %xmm4
[2,0] . DeeE-----R . vmulps %xmm0, %xmm1, %xmm2
[2,1] . D====eeeER . vhaddps %xmm2, %xmm2, %xmm3
[2,2] . D======eeeER vhaddps %xmm3, %xmm3, %xmm4
D
是指令调度,e
指正在进行的执行,E
指其终止,R
指退出。此外,=
表示指令已派发但正在等待执行,而-
表示指令等待退出。
考虑到上面的顺序,是什么阻止了第一个
vhaddps
指令在第二个周期中执行?
我看不出前面的指令之间存在依赖关系。此外,文档还强调,乘法使用
JFPM
和 JFPU1
执行单元,但加法使用其他资源,即 JFPA
和 JFPU0
。加法不应该早点执行吗?
vhaddps
是 3 uop:2 次洗牌和一次垂直添加。 shuffle uop 只能在端口 5 上运行,因此存在资源冲突。这就是为什么 vhaddps
每 2 个周期有一个吞吐量。
(这是在 Intel 上。AMD Zen 2 及更高版本将其解码为 XMM 版本的 4 uops,YMM 版本的 3 uops,奇怪的是。https://uops.info/)。
这就是为什么水平求和一个寄存器是如此糟糕,只有像这里有两个不同的输入才有用。