可以使用 movss 指令替换整数数据吗?
Posted
技术标签:
【中文标题】可以使用 movss 指令替换整数数据吗?【英文标题】:Can a movss instruction be used to replace integer data? 【发布时间】:2016-05-23 01:46:51 【问题描述】:由于我只能使用 SSE 和 SSE2 指令,我需要将 4 元素 __m128i 向量的最低有效 (0) 元素替换为另一个向量中的 0 元素。
对于浮点向量,任务很简单 - 可以使用 _mm_move_ss() 内在函数将元素替换为另一个向量中的 0 元素。它生成一个movss指令,效率很高。
使用两个转换内在函数,还可以说服编译器使用单个 SSE movss 指令来移动整数数据。源代码最终看起来像这样:
__m128i NewVector = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(Take3FromThisVector),
_mm_castsi128_ps(Take1FromThisVector)));
它看起来有点乱,但如果有适当数量的评论,它是可以接受的,特别是因为它生成的指令最少。在其典型使用中,所有内容都经过优化以保存在 xmm 寄存器中。
我的问题是:
由于它是一个 movss 指令,其中“ss”表示单精度浮点,是否可以让它移动可能包含一些“特殊”或“非法”(浮点)组合的整数数据任何向量位置的比特数?
显而易见的替代方法——我也实现并测试了——是与第一个向量与掩码,然后在第二个向量中进行或运算,该向量仅包含最低有效元素中的一个值,而所有其他值都为零。可以想象,这会生成更多指令。
我已经测试了上面展示的强制转换方法,它似乎没有引起任何问题,但我特别注意到,没有提供对整数数据执行相同操作的内在函数。似乎英特尔会提供一个,如果它同样适用于整数数据 - 例如,_mm_move_epi32 或类似的。所以我怀疑这是否是个好主意。
我进行了一些搜索,例如“movss 指令是否会导致浮点异常”,但没有找到任何可以回答我的问题的信息。
提前感谢您愿意分享的知识。
-诺埃尔
【问题讨论】:
另见***.com/questions/13153584/…。不是完全重复,因为关于movss
的怪异设计和与movd
的区别还有很多话要说。
英特尔真的似乎陷入了组装时代。如果实际指令在不指定含义的情况下对位进行混洗,则 C 内在函数应具有 float
和 int
版本。两个具有不同签名的内部函数没有理由不能映射到相同的指令。
我知道,对吧?有点让你想编写一些新的内在内联函数来填补空白。
@MSalters:英特尔终于用__m256
和__m256i
内部函数为vinsertf128
为AVX 做到了这一点。 (vinserti128
仅在 AVX2 中)。当然,只有 AVX1 的 __m256i
并没有什么用处。但这是个好主意。他们绝对应该为shufps
引入整数内在函数,因为在AVX512 的vpermt2d
之前,没有其他类似的方法可以组合来自两个寄存器的数据(置换2 个向量,覆盖表)。
【参考方案1】:
是的,可以在整数数据上使用像 movss xmm, xmm
这样的 FP shuffle。 insn 参考手册告诉你它不能引发 FP 数值异常;只有实际的 FP 数学指令才能做到这一点。所以继续投吧。
在大多数 uarch 中,对整数数据使用 FP shuffle 甚至没有绕过延迟(但在 FP 数学指令之间使用整数 shuffle 会有额外的延迟)。
Agner Fog's "optimizing assembly" guide 有一个很棒的部分,介绍了哪些指令对不同类型的数据移动(广播、合并等)有用。另请参阅x86 标签 wiki 以获得更多好的链接。
没有整数内在函数的原因是 SSE2 movd
整数指令将目标的高字节归零,就像 movss
用作负载,但与寄存器之间的 movss
不同。
英特尔的向量指令集以其不一致和非正交性而闻名,尤其是。最早的版本(如 SSE1)。 SSE4.1填补了很多空白,但仍有明显的缺失。
【讨论】:
【参考方案2】:__m128
和 __m128i
类型可以互换。强制转换的主要原因是让你的意图更清晰(并让你的编译器满意)。演员表本身不会生成任何额外的程序集。
_mm_move_ss
operation 直接根据结果中的哪些位进行描述。
如果单精度浮点数的位组合无效,那么只有在浮点计算中尝试使用结果值时才会出现问题。
【讨论】:
以上是关于可以使用 movss 指令替换整数数据吗?的主要内容,如果未能解决你的问题,请参考以下文章