4

いくつかのサイン値とコサイン値を事前に計算し、それらを整列ブロックに格納し、後で SSE 計算に使用する方法を見つけようとしています。

プログラムの最初に、メンバーを持つオブジェクトを作成します。

static __m128 *m_sincos;

次に、コンストラクターでそのメンバーを初期化します。

m_sincos = (__m128*) _aligned_malloc(Bins*sizeof(__m128), 16);
for (int t=0; t<Bins; t++)
  m_sincos[t] = _mm_set_ps(cos(t), sin(t), sin(t), cos(t));



m_sincos を使用すると、次の 3 つの問題に遭遇します。
-データが整列されていないようです。

movaps xmm0, m_sincos[t] //crashes
movups xmm0, m_sincos[t] //does not crash

-変数が正しくないようです

movaps result, xmm0 // returns values that are not what is in m_sincos[t]
//Although, putting a watch on m_sincos[t] displays the correct values

-私を本当に混乱させているのは、これによりすべてが機能することです(ただし、遅すぎます):

__m128 _sincos = m_sincos[t];
movaps xmm0, _sincos
movaps result, xmm0
4

2 に答える 2

10

m_sincos[t]C式です。ただし、アセンブリ命令 ( __asm?) では、x86 アドレッシング モードとして解釈され、まったく異なる結果になります。たとえば、VS2008 SP1 は次のようにコンパイルします。

movaps xmm0, m_sincos[t]

に: (アプリがデバッグ モードでクラッシュしたときに、逆アセンブリ ウィンドウを参照してください)

movaps xmm0, xmmword ptr [t]

その解釈は、変数のアドレスに格納されている 128 ビット値tを xmm0 にコピーしようとします。 tただし、アラインされていない可能性が高いアドレスの 32 ビット値です。命令を実行すると、アラインメント エラーが発生する可能性が高く、tのアドレスがアラインされている奇妙なケースでは、誤った結果が得られます。

これは、適切な x86 アドレッシング モードを使用して修正できます。遅いが明確なバージョンは次のとおりです。

__asm mov eax, m_sincos                  ; eax <- m_sincos
__asm mov ebx, dword ptr t
__asm shl ebx, 4                         ; ebx <- t * 16 ; each array element is 16-bytes (128 bit) long
__asm movaps xmm0, xmmword ptr [eax+ebx] ; xmm0 <- m_sincos[t]

サイドノート:

これを完全なプログラムに入れると、奇妙なことが起こります。

#include <math.h>
#include <tchar.h>
#include <xmmintrin.h>

int main()
{
    static __m128 *m_sincos;
    int Bins = 4;

    m_sincos = (__m128*) _aligned_malloc(Bins*sizeof(__m128), 16);
    for (int t=0; t<Bins; t++) {
        m_sincos[t] = _mm_set_ps(cos((float) t), sin((float) t), sin((float) t), cos((float) t));
        __asm movaps xmm0, m_sincos[t];
        __asm mov eax, m_sincos
        __asm mov ebx, t
        __asm shl ebx, 4
        __asm movaps xmm0, [eax+ebx];
    }

    return 0;
}

これを実行するとき、レジスタ ウィンドウを監視していると、何かおかしいことに気付くかもしれません。結果は正しいですが、命令が実行されるxmm0に正しい値を取得しています。それはどのように起こりますか?movaps

生成されたアセンブリ コードを見ると_mm_set_ps()、sin/cos の結果が にロードされxmm0、それが のメモリ アドレスに保存されていることがわかりますm_sincos[t]。しかし、価値もそこに残っていxmm0ます。_mm_set_ps関数呼び出しではなく「組み込み」です。完了後に使用するレジスタの値を復元しようとはしません。

このことから得られる教訓があるとすれば、SSE 組み込み関数を使用するときは、それらをずっと使用して、コンパイラーが最適化できるようにすることです。それ以外の場合は、インライン アセンブリを使用している場合は、それも使用してください。

于 2010-06-04T15:58:29.323 に答える
1

組み込み関数を明示的にコーディングするのではなく、常に組み込み関数を使用するか、オンにしてそのままにしておく必要があります。これは、__asm が 64 ビット コードに移植できないためです。

于 2010-06-04T16:55:07.543 に答える