2013-08-30 11 views
8

いくつかの考えた後、私はSSEを使用して2つの四元数を掛けるために、次のコードを思い付いた:2つの四元数に最小限の命令を乗算するにはどうすればよいですか?

#include <pmmintrin.h> /* SSE3 intrinsics */ 

/* multiplication of two quaternions (x, y, z, w) x (a, b, c, d) */ 

__m128 _mm_cross4_ps(__m128 xyzw, __m128 abcd) 
{ 
    /* The product of two quaternions is:         */ 
    /* (X,Y,Z,W) = (xd+yc-zb+wa, -xc+yd+za+wb, xb-ya+zd+wc, -xa-yb-zc+wd) */ 

    __m128 wzyx = _mm_shuffle_ps(xyzw, xyzw, _MM_SHUFFLE(0,1,2,3)); 
    __m128 baba = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(0,1,0,1)); 
    __m128 dcdc = _mm_shuffle_ps(abcd, abcd, _MM_SHUFFLE(2,3,2,3)); 

    /* variable names below are for parts of componens of result (X,Y,Z,W) */ 
    /* nX stands for -X and similarly for the other components    */ 

    /* znxwy = (xb - ya, zb - wa, wd - zc, yd - xc) */ 
    __m128 ZnXWY = _mm_hsub_ps(_mm_mul_ps(xyzw, baba), _mm_mul_ps(wzyx, dcdc)); 

    /* xzynw = (xd + yc, zd + wc, wb + za, yb + xa) */ 
    __m128 XZYnW = _mm_hadd_ps(_mm_mul_ps(xyzw, dcdc), _mm_mul_ps(wzyx, baba)); 

    /* _mm_shuffle_ps(XZYnW, ZnXWY, _MM_SHUFFLE(3,2,1,0)) */ 
    /*  = (xd + yc, zd + wc, wd - zc, yd - xc)  */ 
    /* _mm_shuffle_ps(ZnXWY, XZYnW, _MM_SHUFFLE(2,3,0,1)) */ 
    /*  = (zb - wa, xb - ya, yb + xa, wb + za)  */ 

    /* _mm_addsub_ps adds elements 1 and 3 and subtracts elements 0 and 2, so we get: */ 
    /* _mm_addsub_ps(*, *) = (xd+yc-zb+wa, xb-ya+zd+wc, wd-zc+yb+xa, yd-xc+wb+za)  */ 

    __m128 XZWY = _mm_addsub_ps(_mm_shuffle_ps(XZYnW, ZnXWY, _MM_SHUFFLE(3,2,1,0)), 
           _mm_shuffle_ps(ZnXWY, XZYnW, _MM_SHUFFLE(2,3,0,1))); 

    /* now we only need to shuffle the components in place and return the result  */ 
    return _mm_shuffle_ps(XZWY, XZWY, _MM_SHUFFLE(2,1,3,0)); 

    /* operations: 6 shuffles, 4 multiplications, 3 compound additions/subtractions */ 
} 

私は命令の最小限の量を持っているアセンブリを期待しました。私が間違っているのは何

.text 
    .globl __Z13_mm_cross4_psU8__vectorfS_ 
__Z13_mm_cross4_psU8__vectorfS_: 
LFB594: 
    pushq %rbp 
LCFI0: 
    movq %rsp, %rbp 
LCFI1: 
    subq $232, %rsp 
    movaps %xmm0, -336(%rbp) 
    movaps %xmm1, -352(%rbp) 
    movaps -336(%rbp), %xmm0 
    movaps -336(%rbp), %xmm1 
    shufps $27, %xmm1, %xmm0 
    movaps %xmm0, -16(%rbp) 
    movaps -352(%rbp), %xmm0 
    movaps -352(%rbp), %xmm1 
    shufps $17, %xmm1, %xmm0 
    movaps %xmm0, -32(%rbp) 
    movaps -352(%rbp), %xmm0 
    movaps -352(%rbp), %xmm1 
    shufps $187, %xmm1, %xmm0 
    movaps %xmm0, -48(%rbp) 
    movaps -16(%rbp), %xmm0 
    movaps %xmm0, -112(%rbp) 
    movaps -48(%rbp), %xmm0 
    movaps %xmm0, -128(%rbp) 
    movaps -128(%rbp), %xmm0 
    movaps -112(%rbp), %xmm1 
    mulps %xmm1, %xmm0 
    movaps -336(%rbp), %xmm1 
    movaps %xmm1, -144(%rbp) 
    movaps -32(%rbp), %xmm1 
    movaps %xmm1, -160(%rbp) 
    movaps -160(%rbp), %xmm1 
    movaps -144(%rbp), %xmm2 
    mulps %xmm2, %xmm1 
    movaps %xmm1, -176(%rbp) 
    movaps %xmm0, -192(%rbp) 
    movaps -176(%rbp), %xmm0 
    hsubps -192(%rbp), %xmm0 
    movaps %xmm0, -64(%rbp) 
    movaps -16(%rbp), %xmm0 
    movaps %xmm0, -208(%rbp) 
    movaps -32(%rbp), %xmm0 
    movaps %xmm0, -224(%rbp) 
    movaps -224(%rbp), %xmm0 
    movaps -208(%rbp), %xmm1 
    mulps %xmm1, %xmm0 
    movaps -336(%rbp), %xmm1 
    movaps %xmm1, -240(%rbp) 
    movaps -48(%rbp), %xmm1 
    movaps %xmm1, -256(%rbp) 
    movaps -256(%rbp), %xmm1 
    movaps -240(%rbp), %xmm2 
    mulps %xmm2, %xmm1 
    movaps %xmm1, -272(%rbp) 
    movaps %xmm0, -288(%rbp) 
    movaps -272(%rbp), %xmm0 
    haddps -288(%rbp), %xmm0 
    movaps %xmm0, -80(%rbp) 
    movaps -64(%rbp), %xmm0 
    movaps -80(%rbp), %xmm1 
    shufps $177, %xmm1, %xmm0 
    movaps -80(%rbp), %xmm1 
    movaps -64(%rbp), %xmm2 
    shufps $228, %xmm2, %xmm1 
    movaps %xmm1, -304(%rbp) 
    movaps %xmm0, -320(%rbp) 
    movaps -304(%rbp), %xmm0 
    addsubps  -320(%rbp), %xmm0 
    movaps %xmm0, -96(%rbp) 
    movaps -96(%rbp), %xmm0 
    movaps -96(%rbp), %xmm1 
    shufps $156, %xmm1, %xmm0 
    leave 
LCFI2: 
    ret 

:しかし、ときに私はそれがgccの-msse3 -Sでアセンブリにコンパイルし、結果の関数は、67点の指示を持っていますか?非常に多くの命令を使用せずに要素をシャッフルするより良い方法が必要です。

+0

を組み込み関数アプローチを再設計しようとするかもしれませんほとんどのSIMDでは、複数の操作を1つの操作ではなく並列に実行する必要があります。 SSEの場合、これは4回の四元数乗算(8四元数の乗算)を一度に行う必要があることを意味します。次に水平演算子を使用する必要はなく、SIMD以外のコードの速度を4倍にする必要があります。 –

+0

水平操作を避けるようにしてください - 'xyzw。* dddd + yzwx。* cacA + zwxy。* BbbB - wxyz。* Acac'と(' A = -a、B = -b')。 –

+0

あなたは何を言っているのか分かりますが、四元数はすでに4つの浮動小数点で構成されています。通常、私のコードでは乗算が多いループはありませんが、助けてください。 – Guilherme

答えて

3

気にしないでください。私が代わりに-O1 -S -msse3 gccでコードをコンパイルした場合、私は次の取得:今だけ18の指示にだ

.text 
    .align 4,0x90 
    .globl __Z13_mm_cross4_psU8__vectorfS_ 
__Z13_mm_cross4_psU8__vectorfS_: 
LFB644: 
    movaps %xmm0, %xmm5 
    movaps %xmm1, %xmm3 
    movaps %xmm0, %xmm2 
    shufps $27, %xmm0, %xmm5 
    movaps %xmm5, %xmm4 
    shufps $17, %xmm1, %xmm3 
    shufps $187, %xmm1, %xmm1 
    mulps %xmm3, %xmm2 
    mulps %xmm1, %xmm4 
    mulps %xmm5, %xmm3 
    mulps %xmm1, %xmm0 
    hsubps %xmm4, %xmm2 
    haddps %xmm3, %xmm0 
    movaps %xmm2, %xmm1 
    shufps $177, %xmm0, %xmm1 
    shufps $228, %xmm2, %xmm0 
    addsubps  %xmm1, %xmm0 
    shufps $156, %xmm0, %xmm0 
    ret 

を。それは私が最初に期待したものです。おっとっと。

+3

Nrgh!最適化を有効にせずにパフォーマンスを測定しないでください! –

2

あなたは、Agner FogのC++ vector class libraryに興味があるかもしれません。 SSE2およびAVX命令セットを使用して実装されるQuaternion4fおよびQuaternion4dクラス(もちろん*および*=演算子を含む)を提供します。ライブラリはオープンソースプロジェクトなので、コードを掘り下げて関数を構築するための良い実装例を見つけることができます。

後で、あなたは"optimizing subroutines in assembly language" manualに相談し、機能の最適化された、純粋なアセンブリの実装を提供したり、いくつかの低レベルのトリックを意識しながら、取得するにはC.

+0

私は行列の乗算に関する同様の研究を今行っています。がんばろう! –

+0

ポインタをありがとう。私は "アセンブリ言語でサブルーチンを最適化する"ことを以前に見たことがありましたが、その後それを失いました。 – Guilherme

関連する問題