1

SSEを使用してコードの最適化を開始しました。基本的に、座標を__m128データ型x、y、zに格納することによって一度に4つの光線を処理する光線トレーサーです(4つの光線の座標は軸ごとにグループ化されています)。ただし、ゼロ除算から保護する分岐ステートメントがあり、SSEに変換できないようです。シリアルでは、これは次のとおりです。

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

ここで、wZはz座標であり、この計算は4つの光線すべてに対して実行する必要があります。

これをSSEに変換するにはどうすればよいですか?

私は次のようにSSEequals比較を使用して実験してきました(現在、wzは4つの光線のそれぞれのz値を含む__m128データ型に関係しています):

_mm_cmpeq_ps(_mm_set1_ps(-1.0f) , wZ )

次に、これを使用してwZ [x] = -1.0のケースを特定し、このケースの絶対値を取得して、通常どおり計算を続行します。

しかし、私はこの取り組みであまり成功していません。

4

1 に答える 1

5

これは、さらに最適化することなく、SSEを使用してスカラーコードを実装するだけの非常に簡単なソリューションです。INFたとえば、wZ = -1.0のときに結果が0.5になるという事実を利用するか、または関係なく除算を実行し、事後にsを0.5に変換することによって、おそらくもう少し効率的にすることができます。

SSE4には「ブレンド」命令があり、値をマスクして#ifdef選択するために必要な3つのpre-SSE4命令よりも少し効率的である可能性があるため、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;
}
于 2011-11-04T09:20:10.037 に答える