SSE 从 __m128 中提取整数用于索引数组

Posted

技术标签:

【中文标题】SSE 从 __m128 中提取整数用于索引数组【英文标题】:SSE extracting integers from a __m128 for indexing an array 【发布时间】:2011-11-10 10:03:51 【问题描述】:

在我已转换为 SSE 的一些代码中,我执行了一些光线追踪,使用 __m128 数据类型一次追踪 4 条光线。

在我确定首先击中哪些对象的方法中,我循环遍历所有对象,测试相交并创建一个遮罩,表示哪些光线比之前发现的更早有相交。

我还需要维护与最佳命中时间相对应的对象 ID 数据。我通过维护一个名为 objectNo 的 __m128 数据类型来做到这一点,并使用从交集时间确定的掩码来更新 objectNo,如下所示:

objectNo = _mm_blendv_ps(objectNo,_mm_set1_ps((float)pobj->getID()),mask);

其中 pobj->getID() 将返回一个整数,表示当前对象的 id。进行这种投射并使用混合似乎是更新所有 4 条光线的 objectNo 的最有效方式。

测试完所有交点后,我尝试单独提取 objectNo,并使用它们访问数组以注册交点。最常见的是我尝试过这个:

int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;

但是,这会在 EXC_BAD_ACCESS 中崩溃,因为提取值为 1.0 的浮点数会转换为值为 1065353216 的 int。

如何正确地将 __m128 解压缩为可用于索引数组的整数?

【问题讨论】:

【参考方案1】:

有两个 SSE2 转换内在函数似乎可以满足您的需求:

_mm_cvtps_epi32() _mm_cvttps_epi32()

http://software.intel.com/sites/products/documentation/studio/composer/en-us/2011/compiler_c/intref_cls/common/intref_sse2_int_conversion.htm

这些会将 4 个单精度 FP 转换为 4 个 32 位整数。第一个是通过舍入来完成的。第二个使用截断。

所以它们可以这样使用:

int o0 = _mm_extract_epi32(_mm_cvtps_epi32(objectNo), 0);
prv_noHits[o0]++;

编辑:根据你想要做的,我觉得这可以更好地优化如下:

__m128i ids = _mm_set1_epi32(pobj->getID());

//  The mask will need to change
objectNo = _mm_blend_epi16(objectNo,ids,mask);

int o0 = _mm_extract_epi32(objectNo, 0);
prv_noHits[o0]++;

这个版本摆脱了不必要的转换。但是您需要使用不同的掩码向量。

编辑 2:这是一种无需更换面具的方法:

__m128 ids = _mm_castsi128_ps(_mm_set1_epi32(pobj->getID()));

objectNo = _mm_blendv_ps(objectNo,ids,mask);

int o0 = _mm_extract_ps(objectNo, 0);
prv_noHits[o0]++;

请注意,_mm_castsi128_ps() 内部函数不映射任何指令。这只是从 __m128i__m128 的逐位数据类型转换,以绕过 C/C++ 中的“类型”。

【讨论】:

非常感谢。是的,第二种方式似乎是最佳的,但真正最佳的唯一方式是我可以将 __m128 掩码直接转换为 __m128i 掩码。 使用 EDIT 2 解决方案与使用第一个解决方案时看到的 2.3 相比,我能够实现 3.9 的加速。关于演员阵容成本的一课(_mm_cvtps_epi32)。

以上是关于SSE 从 __m128 中提取整数用于索引数组的主要内容,如果未能解决你的问题,请参考以下文章

将 4 个 SSE 整数提取为 4 个字符

如何在 SSE 中使用 imm8?

SSE 将整数加载到 __m128

SSE 的整数/浮点值

SSE/AVX 向量类型的差异

_mm_extract_epi8(...) 以非文字整数作为参数的内在函数