2012-01-29 3 views
7

私は、音声処理を実行する書き込み中のSSEメソッドに問題があります。私はここでインテルの論文に基づいてSSEランダムな機能を実装しました:SSE組み込み関数は、通常のfloatオペレーションが-1を返すようにします。#INV

次のように私もまた、SSEを使用して、S16にフロートから変換を実行されているメソッドを持って

は、変換は非常に単純に行われ

http://software.intel.com/en-us/articles/fast-random-number-generator-on-the-intel-pentiumr-4-processor/

unsigned int Float_S16LE(float *data, const unsigned int samples, uint8_t *dest) 
{ 
    int16_t *dst = (int16_t*)dest; 
    const __m128 mul = _mm_set_ps1((float)INT16_MAX); 
    __m128 rand; 
    const uint32_t even = count & ~0x3; 
    for(uint32_t i = 0; i < even; i += 4, data += 4, dst += 4) 
    { 
    /* random round to dither */ 
    FloatRand4(-0.5f, 0.5f, NULL, &rand); 

    __m128 rmul = _mm_add_ps(mul, rand); 
    __m128 in = _mm_mul_ps(_mm_load_ps(data),rmul); 
    __m64 con = _mm_cvtps_pi16(in); 

    memcpy(dst, &con, sizeof(int16_t) * 4); 
    } 
} 

次のようにFloatRand4が定義されている:

static inline void FloatRand4(const float min, const float max, float result[4], __m128 *sseresult = NULL) 
{ 
    const float delta = (max - min)/2.0f; 
    const float factor = delta/(float)INT32_MAX; 
    ... 
} 

場合結果が返され、resultは未使用です。 これは最初のループで完全に実行されますが、次のループでdelta1.0ではなく-1.#INFになります。私が__m64 con = _mm_cvtps_pi16(in);という行をコメントアウトすると、問題は解消されます。

私はFPUが未知の状態になっていると思います。

+0

_mm_cvtps_pi16は悪い考えです。 _mm_cvtps_epi32、_mm_packs_epi32、_mm_store_si128/_mm_storeu_si128の組み合わせを使用して8個の浮動小数点数を8個のint16_tに変換し、問題はなくなりました! –

答えて

9

。両方が同じレジスタ上で動作しているので、奇妙な結果を生むことがあります。

_mm_empty() 

FPUは正しい状態にリセットされます。マイクロソフトはGuidelines for When to Use EMMS

+0

正確に問題、ありがとう! – Geoffrey

+1

これは_mm_cvtps_pi16のためだけではありませんか?私は_mm_emptyがMMXだと思った。 _mm_emptyは高価なAFAIKなので、私はこれを置き換えます。 – Sam

+0

はい、これらのFPU命令を廃止して完了するまでSSEに固執するのが正しい解決策ですが、これがなぜ発生したのかを説明する正解でした。 – Geoffrey

1
  • _mm_load_psは、整列された負荷を行うことは保証されていません。 float *データは16バイトではなく4バイトにアライメントすることができます_ => _mm_loadu_ps
  • memcpyはおそらくSSEで得られる利点を無効にしますが、__m64のストアコマンドを使用する必要があります。 アラインされていないストリームまたは__m64のストアを実行できない場合は、_m128iの内部に保持し、_mm_maskmoveu_si128でマスクされた書き込みを実行するか、手動で8バイトを格納します。 SSE整数演算及び(レギュラー)浮動小数点演算を混合

http://msdn.microsoft.com/en-us/library/bytwczae.aspx

+0

ヒントをお寄せいただきありがとうございます。投稿されたサンプルからアライメントコードが省略されているはずです。このメソッドに渡されたデータはすべて整列されています。 – Geoffrey

+0

手で8バイトをどのように保存しますか? – Geoffrey

+1

私は手動でコピーするuint8_t配列[8]を持つユニオンについて考えました。しかし、そのような構造体(とmemcpy)は 'store to load'を引き起こす可能性が常にあるという問題があります。したがって、__int64(またはその2つ)を128ビットレジスタに転送し、それぞれ_mm_maskmoveu_si128または_mm_stream *を実行する方が効率的です。ストリーミングは、一度書かれてすぐにもう一度それを必要としないので、関心のある出力によるキャッシュ汚染を回避します。 – Sam