由于我只能使用SSE和SSE2指令的约束,我需要用另一个向量中的0元素替换4元素__m128i向量的最低有效(0)元素.
对于浮点向量,任务很简单 - 可以使用_mm_move_ss()内在函数来使元素被另一个向量中的0元素替换.它生成一个movss指令,因此效率很高.
使用两个转换内在函数,也可以说服编译器使用单个SSE movss指令来移动整数数据.源代码最终看起来像这样:
__m128i NewVector = _mm_castps_si128(_mm_move_ss(_mm_castsi128_ps(Take3FromThisVector),
_mm_castsi128_ps(Take1FromThisVector)));
Run Code Online (Sandbox Code Playgroud)
它看起来有点乱,但是通过适当的评论量可以接受,特别是因为它产生了最少的指令.在其典型用途中,所有内容都经过优化,可以在xmm寄存器中使用.
我的问题是:
因为它是一个movss指令,其中"ss"意味着单精度浮点,是否可以移动整数数据,这些数据可能包含某些"特殊"或"非法"(用于浮点)任何一个位的组合矢量位置?
显而易见的替代方案 - 我也实现并测试过 - 是使用掩码对第一个向量进行AND运算,然后在第二个向量中使用OR,该向量仅包含最低有效元素中的一个值,其他所有值均为零.可以想象,这会产生更多指令.
我已经测试了我上面展示的转换方法并且它似乎没有引起任何问题,但我特别注意到没有为整数数据执行相同操作的内在提供.似乎英特尔会提供一个,如果它对整数数据一样好 - 例如,_mm_move_epi32或类似的.所以我怀疑这是不是一个好主意.
我做了一些搜索,例如"可以使用movss指令导致浮点异常",但没有找到任何可以回答我问题的信息.
提前感谢您愿意分享的知识.
-Noel
在使用浮点数据的C++代码中,通常使用舍入从float转换为int.例如,一种用途是生成转换表.
考虑这段代码:
// Convert a positive float value and round to the nearest integer
int RoundedIntValue = (int) (FloatValue + 0.5f);
Run Code Online (Sandbox Code Playgroud)
C/C++语言将(int)强制转换定义为截断,因此必须添加0.5f以确保向上舍入到最接近的正整数(当输入为正时).对于上述内容,VS2015的编译器生成以下代码:
movss xmm9, DWORD PTR __real@3f000000 // 0.5f
addss xmm0, xmm9
cvttss2si eax, xmm0
Run Code Online (Sandbox Code Playgroud)
以上工作,但可能更有效......
英特尔的设计人员显然认为使用单个指令解决问题非常重要,只需要做的就是:转换为最接近的整数值:cvtss2si(注意,在助记符中只有一个't').
如果cvtss2si要在上面的序列中替换cvttss2si指令,那么就会消除三个指令中的两个(就像使用额外的xmm寄存器一样,这可能会导致更好的整体优化).
那么我们如何编写C++语句来使用一个cvtss2si指令完成这个简单的工作呢?
我一直在四处寻找,尝试以下内容,但即使使用优化器执行任务,它也不能归结为可以/应该完成工作的一台机器指令:
int RoundedIntValue = _mm_cvt_ss2si(_mm_set_ss(FloatValue));
Run Code Online (Sandbox Code Playgroud)
不幸的是,上面似乎倾向于清除永远不会使用的整个寄存器向量,而不是仅使用一个32位值.
movaps xmm1, xmm0
xorps xmm2, xmm2
movss xmm2, xmm1
cvtss2si eax, xmm2
Run Code Online (Sandbox Code Playgroud)
也许我在这里错过了一个明显的方法.
你能提供一套建议的C++指令,最终会生成单个cvtss2si指令吗?