vextracti128
和vextractf128
具有相同的功能,参数和返回值。另外一个是AVX指令集,而另一个是AVX2。有什么不同?
答案 0 :(得分:11)
vextracti128
和vextractf128
不仅具有相同的功能,参数和返回值。它们具有相同的指令长度。并且它们具有相同的吞吐量(根据Agner Fog的优化手册)。
不完全清楚的是它们的延迟值(具有依赖链的紧密循环中的性能)。指令本身的延迟是3个周期。但在阅读英特尔优化手册的2.1.3节(“执行引擎”)之后,我们可能会怀疑vextracti128
在处理浮点数据时应该额外延迟1个时钟延迟,而vextractf128
应该会额外延长1个时钟延迟使用整数数据时。测量表明这不是真的,延迟总是保持3个周期(至少对于Haswell处理器而言)。据我所知,优化手册中的任何地方都没有记录。
静止指令集只是处理器的接口。 Haswell是此接口的唯一实现,包含这两个指令(暂时)。我们可以忽略这些指令的实现(很可能)相同的事实。并按预期使用这些说明 - vextracti128
表示整数数据,vextractf128
表示FP数据。 (如果我们只需要在不执行任何int / FP操作的情况下重新排序数据,那么显而易见的选择是vextractf128
,因为几个较旧的处理器支持它。经验表明,英特尔有时会降低下一代CPU中某些指令的性能,因此明智地遵守这些指令的亲和性,以避免将来出现任何可能的速度降级。
由于英特尔优化手册不是非常详细地描述了用于SIMD指令的int / FP域之间的关系,我已经做了一些测量(在Haswell上)并得到了一些有趣的结果:
SSE整数和随机指令之间的任何转换都没有额外的延迟。并且SSE FP和shuffle指令之间的任何转换都没有额外的延迟。 (虽然我没有测试每条指令)。例如,您可以在两条FP指令之间插入pshufb
这样的“明显整数”指令而不会有额外的延迟。在整数代码的中间插入shufpd
也不会产生额外的延迟。
由于shuffle单位执行vextracti128
和vextractf128
,因此它们也具有“无延迟”属性。
这可能对优化混合int + FP代码很有用。如果您需要将FP数据重新解释为整数并同时对寄存器进行洗牌,只需确保所有FP指令都在shuffle之前,并且所有整数指令都在它之后。
andps
和其他FP逻辑指令也具有忽略FP / int域的属性。
如果在FP代码中添加整数逻辑指令(如pand
),则会产生额外的2个周期延迟(一个到达int域,另一个到达FP)。因此,SIMD FP代码的明显选择是andps
。可以在整数代码的中间使用相同的andps
而没有任何延迟。更好的是在int和FP指令之间使用这样的指令。有趣的是,FP逻辑指令使用与所有shuffle指令相同的端口号5。
英特尔优化手册介绍了生产者和消费者微操作之间的旁路延迟。但它并没有说明微操作如何与寄存器相互作用。
这段代码每次迭代只需要3个时钟(正如vaddps
所要求的那样):
vxorps ymm7, ymm7, ymm7
_benchloop:
vaddps ymm0, ymm0, ymm7
jmp _benchloop
但是这个每次迭代需要2个时钟(比vpaddd
需要多1个时钟):
vpxor ymm7, ymm7, ymm7
_benchloop:
vpaddd ymm0, ymm0, ymm7
jmp _benchloop
这里唯一的区别是整数域而不是FP域的计算。要获得1个时钟/迭代,我们需要添加一条指令:
vpxor ymm7, ymm7, ymm7
_benchloop:
vpand ymm6, ymm7, ymm7
vpaddd ymm0, ymm0, ymm6
jmp _benchloop
提示:(1)存储在SIMD寄存器中的所有值都属于FP域,(2)从SIMD寄存器读取会使整数运算的延迟增加1。 (这里{ymm0,ymm6}和ymm7之间的区别在于ymm7存储在一些临时存储器中并且作为真正的“寄存器”工作,而ymm0和ymm6是临时的并且由内部CPU的互连状态而不是某些永久存储器表示,所以ymm0和ymm6不是“读”但只是在微操作之间传递。
答案 1 :(得分:3)
好问题 - 看起来AVX指令vextractf128
适用于任何矢量类型(int,float,double),而AVX2指令vextracti128
仅适用于int矢量。如果你有AVX2和整数向量,我推荐使用后者,以防它在某些情况下提供更好的性能,否则使用前者。