我有一个AVX CPU(不支持AVX2),我想计算两个256位整数的按位xor.
由于_mm256_xor_si256
仅在AVX2上可用,我可以将这256位加载为__m256
使用_mm256_load_ps
,然后执行a _mm256_xor_ps
.这会产生预期的结果吗?
我主要担心的是,如果内存内容不是有效的浮点数,_mm256_load_ps
那么寄存器中的位不会与寄存器中的位完全相同吗?
谢谢.
首先,如果你正在使用256b整数做其他事情(比如加/减/乘),将它们放入向量寄存器只是为了偶尔的异或可能不值得转移它们的开销.如果寄存器中已有两个数字(使用最多8个寄存器),则只有四条xor
指令可以获得结果(mov
如果需要避免覆盖目标,则只有4 条指令).破坏性版本可以在SnB上每1.33个时钟周期运行一次,或者在Haswell及更高版本上每个时钟运行一个.(xor
可以在4个ALU端口中的任何一个上运行).所以如果你只是xor
在某些add/adc
或其他什么之间做一个,坚持使用整数.
以64b块存储到内存然后执行128b或256b负载会导致存储转发失败,从而增加了几个延迟周期.使用movq
/ pinsrq
将花费更多的执行资源xor
.走另一条路并没有那么糟糕:256b商店 - > 64b负载适用于商店转发. movq
/ pextrq
仍然很糟糕,但会有更低的延迟(以更多uops为代价).
FP加载/存储/按位操作在架构上保证不产生FP异常,即使在表示信令NaN的位模式上使用时也是如此.只有实际的FP数学指令列出了数学异常:
VADDPS
SIMD浮点异常
溢出,下溢,无效,精度,非正常.
VMOVAPS
SIMD浮点异常
无.
(来自英特尔的insn参考手册.请参阅x86 wiki以获取该链接和其他内容.)
在英特尔硬件上,加载/存储的风格可以在没有额外延迟的情况下进入FP或整数域.无论数据来自何处,AMD都使用类似的行为,无论使用何种风格的加载/存储.
不同风格的向量移动指令实际上对于寄存器<-register移动很重要.在Intel Nehalem上,使用错误的mov指令可能会导致旁路延迟.在AMD Bulldozer系列中,通过寄存器重命名处理移动而不是实际复制数据(如Intel IvB及更高版本),dest寄存器继承了src寄存器写入的域.
我读过的现有设计没有movapd
任何不同的处理方式movaps
.据推测,英特尔movapd
为解码简单性创建了与未来规划相同的功能(例如,允许设计中存在双域和单域,具有不同转发网络的设计).(movapd
是movaps
有66h
前缀的,就像所有其他的SSE指令只是拥有的双版本66h
前缀字节的上涨,或者F2
代替F3
了标量指令.)
显然AMD设计了带有辅助信息的FP矢量标签,因为例如,当使用输出addps
作为输入时,Agner Fog发现了很大的延迟addpd
.我不认为movaps
两个addpd
指令之间,甚至xorps
会导致这个问题:只有实际的FP数学.(FP按位布尔运算是Bulldozer-family上的整数域.)
Intel SnB/IvB(唯一具有AVX而非AVX2的Intel CPU)的理论吞吐量:
xorps
VMOVDQU ymm0, [A] VXORPS ymm0, ymm0, [B] VMOVDQU [result], ymm0
由于流水线宽度为4个融合域uops,因此3个融合域uop可以每0.75个周期发出一个.(假设你用于B的寻址模式和结果可以微融合,否则它是5个融合域uops.)
加载端口:SnB上的256b加载/存储需要2个周期(分成128b两半),但这会释放存储器使用的端口2/3上的AGU.有一个专用的存储数据端口,但存储地址计算需要来自加载端口的AGU.
因此,只有128b或更小的加载/存储,SnB/IvB每个周期可以维持两个存储器操作(其中至多一个是存储).对于256b操作,SnB/IvB理论上可以支持两个256b负载和每两个周期一个256b存储.但是,缓存库冲突通常会使这种情况变得不可能.
Haswell有一个专用的存储地址端口,每个周期可以支持两个256b负载和一个256b存储,并且没有缓存存储区冲突.因此,当所有内容都在L1缓存中时,Haswell会更快.
底线:理论上(没有缓存库冲突),这应该使SnB的加载和存储端口饱和,每个周期处理128b.xorps
每两个时钟需要一次Port5(唯一可以运行的端口).
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上,VPXOR
每个时钟三个AVX2 256b 将在每个周期中提供最多的异或.(XORPS
并PXOR
做同样的事情,但是XORPS
输出可以转发到FP执行单元而没有额外的转发延迟周期.我想只有一个执行单元的接线在FP域中有一个XOR结果,所以Intel CPUs后Nehalem只在一个端口上运行XORPS.)
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
甚至更多的融合域uops(8),而不仅仅是做128b-一切.
加载/存储:两个256b负载留下两个备用周期,用于生成两个存储地址,因此这仍然可以在两个负载/每个周期128b的一个存储中运行.
ALU:两个端口-5 uops(vextractf128),两个端口0/1/5 uop(vpxor).
因此,每2个时钟的吞吐量仍然是一个256b的吞吐量,但它的资源更多,并且在3指令256b版本上没有优势(在Intel上).