X86 SSE:将短整数转换为浮点

X86 SSE:将短整数转换为浮点,x86,sse,simd,X86,Sse,Simd,我想使用SSE将无符号短数字数组转换为浮点。比方说 __m128i xVal; // Has 8 16-bit unsigned integers __m128 y1, y2; // 2 xmm registers for 8 float values 我想要y1中的前4个uint16和y2中的下4个uint16。 需要知道要使用哪个sse内在函数。您需要首先将8 x 16位无符号短路向量解压缩为两个32位无符号整数向量,然后将每个向量转换为浮点: __m128i xlo = _

我想使用SSE将无符号短数字数组转换为浮点。比方说

__m128i xVal;     // Has 8 16-bit unsigned integers
__m128 y1, y2;    // 2 xmm registers for 8 float values
我想要y1中的前4个uint16和y2中的下4个uint16。
需要知道要使用哪个sse内在函数。

您需要首先将8 x 16位无符号短路向量解压缩为两个32位无符号整数向量,然后将每个向量转换为浮点:

__m128i xlo = _mm_unpacklo_epi16(x, _mm_set1_epi16(0));
__m128i xhi = _mm_unpackhi_epi16(x, _mm_set1_epi16(0));
__m128 ylo = _mm_cvtepi32_ps(xlo);
__m128 yhi = _mm_cvtepi32_ps(xhi);

我建议使用稍微不同的版本:

static const __m128i magicInt = _mm_set1_epi16(0x4B00);
static const __m128 magicFloat = _mm_set1_ps(8388608.0f);

__m128i xlo = _mm_unpacklo_epi16(x, magicInt);
__m128i xhi = _mm_unpackhi_epi16(x, magicInt);
__m128 ylo = _mm_sub_ps(_mm_castsi128_ps(xlo), magicFloat);
__m128 yhi = _mm_sub_ps(_mm_castsi128_ps(xhi), magicFloat);

在汇编级别上,与Paul R版本的唯一区别是使用了_mm_sub_ps(SUBPS指令)而不是_mm_cvtepi32_ps(CVTDQ2PS指令)_mm_sub_ps的速度永远不会比_mm_cvtepi32_ps慢,而且在旧CPU和低功耗CPU(读:Intel Atom和AMD Bobcat)上的速度实际上更快。

不过,我并不完全相信这会更好。将数据从SSE int移动到SSE-FP需要1-2个周期的延迟。然后,需要为这两个常量添加两个额外的寄存器(或加载)。此技巧更常用于双精度。CVTDQ2PS还受到SSE-INT到SSE-FP转换惩罚的影响。寄存器压力增加可能是一个问题,但它高度依赖于周围的代码。我也会这样做,只是我会使用一个_mm_setzero_si128(),而不是两个_mm_set1_epi16。@Magnus:我想你会发现生成的代码是相同的,至少在大多数体面的编译器中是如此。@PaulR Hi Paul。优化器倾向于做一些事情,但不是我会做的事情:-)在这种情况下,我发现至少MSVC将_mm_set1_epi16(0)折叠成一个16字节的常量,它使用movdqa加载该常量。它实际上使用两个单独的movdqa指令生成两个常量。我发现MSVC在生成/优化SSE代码时有点不可靠——有时还可以,有时则失败得很惨。gcc、ICC和clang都倾向于更加一致/可靠。@PaulR。有些情况下,我被不同的编译器抓住了,这让我非常悲观,但事实上,他们确实经常设法做正确的事情。