首先,如果您正在使用 256b 整数做其他事情(例如加/减/乘),将它们放入向量寄存器中只是为了偶尔进行异或可能不值得转移它们的开销。如果寄存器中已经有两个数字(总共使用 8 个寄存器),则只需 4 条 xor 指令即可获得结果(如果需要避免覆盖目标,则需要 4 条 mov 指令)。破坏性版本可以在 SnB 上以每 1.33 个时钟周期运行一次,或在 Haswell 及更高版本上以每时钟一次运行。 (xor 可以在 4 个 ALU 端口中的任何一个上运行)。因此,如果您只是在一些 add/adc 或其他任何东西之间做一个 xor,请坚持使用整数。
以 64b 块存储到内存,然后执行 128b 或 256b 加载将cause a store-forwarding failure,增加另外几个延迟周期。使用movq / pinsrq 会比xor 花费更多的执行资源。采用另一种方式并没有那么糟糕:256b 存储 -> 64b 负载适用于存储转发。 movq / pextrq 仍然很糟糕,但延迟会更低(以更多微指令为代价)。
FP 加载/存储/按位操作在架构上保证不会产生 FP 异常,即使在用于表示信号 NaN 的位模式时也是如此。只有实际的 FP 数学指令会列出数学异常:
VADDPS
SIMD 浮点异常
上溢、下溢、无效、
精度,非正规。
VMOVAPS
SIMD 浮点异常
没有。
(来自英特尔的 insn 参考手册。请参阅 x86 wiki 以获取指向该内容和其他内容的链接。)
在 Intel 硬件上,任一类型的加载/存储都可以转到 FP 或整数域,而无需额外延迟。无论数据去往/来自何处,AMD 的行为相似,无论使用哪种加载/存储方式。
不同风格的向量移动指令actually matter for register<-register moves。在 Intel Nehalem 上,使用错误的 mov 指令会导致绕过延迟。在 AMD Bulldozer 系列中,移动是通过寄存器重命名而不是实际复制数据来处理的(如 Intel IvB 及更高版本),dest 寄存器继承了写入 src 寄存器的域。
我所读到的现有设计对movapd 的处理与movaps 没有任何不同。据推测,英特尔创建movapd 的目的与解码简单性和未来规划一样多(例如,允许设计有双域和单域,具有不同的转发网络)。 (movapd 是带有 66h 前缀的 movaps,就像所有其他 SSE 指令的双版本一样,只是添加了 66h 前缀字节。或者对于标量指令,使用 F2 而不是 F3。)
显然,AMD 设计了带有辅助信息的标记 FP 向量,因为例如,当使用 addps 的输出作为 addpd 的输入时,Agner Fog found 会有很大的延迟。我不认为两个addpd 指令之间的movaps 甚至xorps 会导致这个问题,但是:只有实际的FP 数学。 (FP 位布尔运算是 Bulldozer 系列上的整数域。)
Intel SnB/IvB(唯一具有 AVX 而不是 AVX2 的 Intel CPU)上的理论吞吐量:
256b AVX 操作xorps
VMOVDQU ymm0, [A]
VXORPS ymm0, ymm0, [B]
VMOVDQU [result], ymm0
每 0.75 个周期可以发出 3 个融合域微指令,因为流水线宽度为 4 个融合域微指令。 (假设您用于 B 和 result 的寻址模式可以微融合,否则它是 5 个融合域微指令。)
-
加载端口:SnB 上的 256b 加载/存储需要 2 个周期(分成 128b 的两半),但这释放了端口 2/3 上的 AGU 以供存储使用。有一个专用的存储数据端口,但存储地址计算需要来自加载端口的 AGU。
因此,只有 128b 或更小的加载/存储,SnB/IvB 可以在每个周期维持两个内存操作(其中最多一个是存储)。对于 256b 操作,SnB/IvB 理论上可以每两个周期维持两个 256b 负载和一个 256b 存储。不过,缓存组冲突通常使这成为不可能。
Haswell 有一个专用的存储地址端口,每个周期可以承受两个 256b 负载和一个 256b 存储,并且没有缓存组冲突。因此,当所有内容都在 L1 缓存中时,Haswell 会快得多。
底线:理论上(没有缓存库冲突)这应该使 SnB 的加载和存储端口饱和,每个周期处理 128b。每两个时钟需要一次端口5(唯一可以运行的端口xorps)。
128b 操作
VMOVDQU xmm0, [A]
VMOVDQU xmm1, [A+16]
VPXOR xmm0, xmm0, [B]
VPXOR xmm1, xmm1, [B+16]
VMOVDQU [result], xmm0
VMOVDQU [result+16], xmm1
这将成为地址生成的瓶颈,因为 SnB 每个周期只能维持两个 128b 内存操作。它还将在 uop 缓存中使用 2 倍的空间,以及更多的 x86 机器代码大小。除非缓存库发生冲突,否则这应该以每 3 个时钟一次 256b-xor 的吞吐量运行。
在寄存器中
在寄存器之间,每个时钟一个 256b VXORPS 和两个 128b VPXOR 会使 SnB 饱和。在 Haswell 上,每个时钟三个 AVX2 256b VPXOR 将在每个周期提供最多的 XOR-ing。 (XORPS 和PXOR 做同样的事情,但是XORPS 的输出可以转发到 FP 执行单元,而无需额外的转发延迟周期。我猜只有一个执行单元具有 XOR 结果的接线FP 域,so Intel CPUs post-Nehalem only run XORPS on one port。)
Z Boson 的混合想法:
VMOVDQU ymm0, [A]
VMOVDQU ymm4, [B]
VEXTRACTF128 xmm1, ymm0, 1
VEXTRACTF128 xmm5, ymm1, 1
VPXOR xmm0, xmm0, xmm4
VPXOR xmm1, xmm1, xmm5
VMOVDQU [res], xmm0
VMOVDQU [res+16], xmm1
比仅仅做 128b-everything 更多的融合域微指令 (8)。
加载/存储:两次 256b 加载为生成两个存储地址留下了两个空闲周期,因此它仍然可以在每个周期以两次加载/一次 128b 存储运行。
ALU:两个端口 5 微指令 (vextractf128),两个端口 0/1/5 微指令 (vpxor)。
因此,这仍然具有每 2 个时钟一个 256b 结果的吞吐量,但它会占用更多资源,并且与 3 指令 256b 版本相比(在 Intel 上)没有优势。