为什么“PSHUFD”指令没有固有的浮点?

时间:2017-04-19 12:10:42

标签: c++ assembly vectorization sse intrinsics

我面临的任务是洗牌一个 _m128向量并将结果存储在另一个向量中。

我看到它的方式,有两种基本方法可以混合打包的浮点_m128向量:

  • _mm_shuffle_ps,它使用SHUFPS指令,如果只想要来自一个向量的值,则不一定是最佳选项:它从目标操作数中获取两个值,这意味着额外的移动。 / LI>
  • _mm_shuffle_epi32,它使用PSHUFD指令似乎完全符合预期,并且可以具有比SHUFPS更好的延迟/吞吐量。

然而,后者的内在函数与整数向量(_m128i)一起工作,并且似乎没有浮点对应,因此将它与_m128一起使用将需要一些丑陋的显式转换。事实上,没有这样的对手可能意味着有一些正当的理由,我不知道。

问题是为什么没有固有的内容可以将一个浮点向量移动并将结果存储在另一个中? 如果_mm_shuffle_ps(x,x, ...)可以生成PSHUFPD,是否可以保证? 如果PSHUFD不应该用于浮点值,那么原因是什么?

谢谢!

1 个答案:

答案 0 :(得分:3)

内在函数应该与指令一对一地映射。 _mm_shuffle_ps生成PSHUFD是非常不受欢迎的。它应该始终生成SHUFPS。该文档并未表明存在其他情况。

当数据转换为单精度或双精度浮点时,某些处理器会有性能下降。这是因为处理器利用包含数据的FP分类的内部寄存器来增加SSE寄存器,例如,零或NaN或无穷大或正常。切换类型时,在执行该步骤时会产生停顿。我不知道现代处理器是否仍然如此,但您可以参考英特尔架构优化手册获取该信息。

在现代处理器上,SHUFPS并不比PSHUFD慢得多。根据Agner Fog的指令表(http://www.agner.org/optimize/instruction_tables.pdf),它们在Haswell(第4代Core i7)上具有相同的延迟和吞吐量。在Nehalem(第一代Core i7)上,它们具有相同的延迟,但PSHUFD的吞吐量为2 /周期,SHUFPS的吞吐量为1 /周期。因此,即使您忽略了与切换类型相关的性能损失,也不能说一条指令应优先于所有处理器中的另一条指令。

还有一种方法可以在__m128,__ m128d和__m128i:_mm_castXX_YY(https://software.intel.com/en-us/node/695375?language=es)之间进行投射,其中XX和YY分别是ps,pd或si128。例如,_ mm_castps_pd()。这实际上是一个坏主意,因为PSHUFD更快的处理器会受到与之后切换回FP相关的性能损失的影响。换句话说,除了做SHUFPS之外,没有更快的方法来做SHUFPS。