SSE从__m128中提取整数以索引数组

时间:2011-11-10 10:03:51

标签: c++ sse

在我转换为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 个答案:

答案 0 :(得分:4)

有两个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 ++中的“类型性”。