2011-11-04 424 views
1

我已经开始使用SSE优化我的代码。本质上,它是一个光线跟踪器,通过将坐标存储在__m128数据类型x,y,z中(四个光线的坐标按轴分组),一次处理4条光线。然而,我有一个分支声明,它可以防止零除以我似乎无法转换为SSE。这是:用于比较的SSE内在函数(_mm_cmpeq_ps)和赋值操作

const float d = wZ == -1.0f ? 1.0f/(1.0f-wZ) : 1.0f/(1.0f+wZ); 

其中wZ是z坐标,这个计算需要对所有四条射线完成。

我怎么能把这个翻译成SSE?

我已经使用SSE等于比较如下(现在WZ涉及一种__m128数据类型包含每个的四个射线的z值)进行实验:

_mm_cmpeq_ps(_mm_set1_ps(-1.0f) , wZ) 

,然后使用这个识别的情况下其中wZ [x] = -1.0,取这种情况的绝对值,然后继续正常的计算。

但是我在这方面没有取得太大的成功。

+1

除以零有什么问题? – Pubby

+0

除了明显的问题之外,它还会通过在算法的其余部分为Nz = -1创建不一致性来破坏结果。 – cubiclewar

回答

4

这是一个相当直接的解决方案,它只是用SSE实现标量代码而不需要进一步优化。它可能会更有效率,例如通过利用当wZ = -1.0时结果为0.5的事实,或者甚至可以通过仅仅进行除法,然后在事实之后将INF s转换为0.5来实现。

对于SSE4与pre-SSE4,我已经有#ifdef d了,因为SSE4有一个“混合”指令,这个指令可能更有效一些屏蔽和选择值所需的三个预先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; 
} 
+0

正是我以前的样子。我需要仔细阅读一些操作才能完全理解代码,但我会生成正确的结果。出于好奇可以在SSE中容易识别并替换(infinite或nan(1/0评估的内容))? – cubiclewar

+0

我还没有尝试过,但我*认为*,你可以利用'_mm_cmpeq_ps(v,v)''当'v'是'INF'或'NaN'时会返回false - 我可以尝试使用另一个解决方案这个方法后来如果我得到时间... –

+1

我试了@ PaulR的建议,用'_mm_cmpeq_ps(v,v)'作为位掩码来过滤掉'INF' /'NaN',它似乎工作正常。 – Rotem