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 中提取整数用于索引数组的主要内容,如果未能解决你的问题,请参考以下文章