2011-11-04 425 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