用于比较 (_mm_cmpeq_ps) 和赋值操作的 SSE 内在函数
Posted
技术标签:
【中文标题】用于比较 (_mm_cmpeq_ps) 和赋值操作的 SSE 内在函数【英文标题】:SSE intrinsics for comparison (_mm_cmpeq_ps) and assignment operation 【发布时间】:2011-11-04 03:56:59 【问题描述】:我已经开始使用 SSE 优化我的代码。本质上,它是一个光线追踪器,通过将坐标存储在 __m128 数据类型 x、y、z 中来一次处理 4 条光线(四条光线的坐标按轴分组)。但是,我有一个分支语句可以防止被零除,我似乎无法转换为 SSE。在串行是:
const float d = wZ == -1.0f ? 1.0f/( 1.0f-wZ) : 1.0f/(1.0f+wZ);
其中 wZ 是 z 坐标,需要对所有四条射线进行此计算。
我怎样才能把它翻译成 SSE?
我一直在尝试使用 SSE equals 比较,如下所示(现在 wz 属于 __m128 数据类型,其中包含四个射线中每一个的 z 值):
_mm_cmpeq_ps(_mm_set1_ps(-1.0f) , wZ )
然后用它来识别wZ[x] = -1.0的情况,取这种情况的绝对值,然后照常继续计算。
但是我在这方面的努力并没有取得太大的成功。
【问题讨论】:
除以零有什么问题? 除了明显的问题外,它会通过在 Nz = -1 处为算法的其余部分创建不一致来破坏结果。 【参考方案1】:这是一个相当简单的解决方案,它只是使用 SSE 实现标量代码,无需任何进一步优化。它可能会变得更有效率,例如通过利用当 wZ = -1.0 时结果为 0.5 的事实,或者甚至可以只进行除法,然后在事后将 INF
s 转换为 0.5。
对于 SSE4 与 pre-SSE4 相比,我有 #ifdef
d,因为 SSE4 有一个“混合”指令,它可能比另外三个需要屏蔽和选择值的 pre-SSE4 指令更有效。
#include <emmintrin.h>
#ifdef __SSE4_1__
#include <smmintrin.h>
#endif
#include <stdio.h>
int main(void)
const __m128 vk1 = _mm_set1_ps(1.0f); // useful constants
const __m128 vk0 = _mm_set1_ps(0.0f);
__m128 wZ, d, d0, d1, vcmp;
#ifndef __SSE4_1__ // pre-SSE4 implementation
__m128 d0_masked, d1_masked;
#endif
wZ = _mm_set_ps(-1.0f, 0.0f, 1.0f, 2.0f); // test inputs
d0 = _mm_add_ps(vk1, wZ); // d0 = 1.0 - wZ
d1 = _mm_sub_ps(vk1, wZ); // d1 = 1.0 + wZ
vcmp = _mm_cmpneq_ps(d1, vk0); // test for d1 != 0.0, i.e. wZ != -1.0
#ifdef __SSE4_1__ // SSE4 implementation
d = _mm_blendv_ps(d0, d1, vcmp);
#else // pre-SSE4 implementation
d0_masked = _mm_andnot_ps(vcmp, d0);
d1_masked = _mm_and_ps(vcmp, d1);
d = _mm_or_ps(d0_masked, d1_masked); // d = wZ == -1.0 ? 1.0 / (1.0 - wZ) : 1.0 / (1.0 + wZ)
#endif
d = _mm_div_ps(vk1, d);
printf("wZ = %vf\n", wZ);
printf("d = %vf\n", d);
return 0;
【讨论】:
正是我所追求的。我需要阅读一些操作才能完全理解代码,但我会生成正确的结果。出于好奇,是否可以在 SSE 中轻松识别并替换 inf 或 nan(1/0 的计算结果)? 我没有尝试过,但我认为当v
是INF
或NaN
时,_mm_cmpeq_ps(v, v)
将返回 false -如果我有时间,我稍后可能会尝试使用此方法的另一种解决方案...
我尝试了@PaulR 的建议,使用_mm_cmpeq_ps(v, v)
作为位掩码过滤掉INF
/NaN
,它似乎工作正常。
它可以识别 INF 或 NaN。要区分这两者,您可以将绝对值与 _mm_set1_ps(__builtin_inff()) 或在 Windows 上比较 _mm_set1_ps(HUGE_VALF)以上是关于用于比较 (_mm_cmpeq_ps) 和赋值操作的 SSE 内在函数的主要内容,如果未能解决你的问题,请参考以下文章