17

__m128フロートが16バイトに整列されている場合、フロートを直接キャストすることは安全/可能/推奨されますか?

_mm_load_ps生の配列を使用し_mm_store_psて「ラップ」すると、かなりのオーバーヘッドが発生することに気づきました。

私が知っておくべき潜在的な落とし穴は何ですか?

編集 :

ロードおよびストア命令を使用する際のオーバーヘッドは実際にはありません。いくつかの数値が混在しているため、パフォーマンスが向上しました。インスタンスで生のメモリアドレスを使って恐ろしいマングリングを行うことができたとしても__m128、テストを実行すると、_mm_load_ps命令なしで完了するのに2倍の時間がかかり、おそらくフェイルセーフコードパスにフォールバックしました。

4

5 に答える 5

11

何があなたにそれを考えさせ_mm_load_ps_mm_store_ps「かなりのオーバーヘッドを追加する」のですか?これは、ソース/宛先がメモリであると仮定して、SSEレジスタとの間でfloatデータをロード/ストアする通常の方法です(そして、他の方法は最終的にこれに要約されます)。

于 2012-08-01T13:11:31.870 に答える
8

floatSSEレジスタに値を入れる方法はいくつかあります。次の組み込み関数を使用できます。

__m128 sseval;
float a, b, c, d;

sseval = _mm_set_ps(a, b, c, d);  // make vector from [ a, b, c, d ]
sseval = _mm_setr_ps(a, b, c, d); // make vector from [ d, c, b, a ]
sseval = _mm_load_ps(&a);         // ill-specified here - "a" not float[] ...
                                  // same as _mm_set_ps(a[0], a[1], a[2], a[3])
                                  // if you have an actual array

sseval = _mm_set1_ps(a);          // make vector from [ a, a, a, a ]
sseval = _mm_load1_ps(&a);        // load from &a, replicate - same as previous

sseval = _mm_set_ss(a);           // make vector from [ a, 0, 0, 0 ]
sseval = _mm_load_ss(&a);         // load from &a, zero others - same as prev

_mm_set_ss(val)コンパイラは、記述したかどうかに関係なく、同じ命令を作成することがよくあります_mm_load_ss(&val)。それを試して、コードを逆アセンブルしてください。

場合によっては、コード(の構造)に応じて..._mm_set_ss(*valptr)の代わりに記述する方が有利な場合があります。_mm_load_ss(valptr)

于 2012-08-01T19:23:17.310 に答える
6

http://msdn.microsoft.com/en-us/library/ayeb3ayc.aspxによると、それは可能ですが、安全ではなく、推奨されていません

__m128フィールドに直接アクセスしないでください。


そして、その理由は次のとおりです。

http://social.msdn.microsoft.com/Forums/en-US/vclanguage/thread/766c8ddc-2e83-46f0-b5a1-31acbb6ac2c5/

  1. float*を__m128にキャストしても機能しません。C ++コンパイラは、割り当てを__m128タイプからSSE命令に変換し、4つの浮動小数点数をSSEレジスタにロードします。このキャストがコンパイルされていると仮定すると、SEEロード命令が生成されないため、動作するコードは作成されません。

__m128変数は、実際には変数または配列ではありません。これはSSEレジスタのプレースホルダーであり、C++コンパイラからSSEアセンブリ命令に置き換えられます。これをよりよく理解するには、インテルアセンブリプログラミングリファレンスをお読みください。

于 2012-08-01T12:59:04.637 に答える
5

質問されてから数年が経ちました。私の経験が示す質問に答えるために:

はい

reinterpret_cast-16バイトにアラインされている限り、afloat*をaにキャストしたり__m128*、その逆を行ったりすることは適切float*です-例(MSVC 2012の場合):

__declspec( align( 16 ) ) float f[4];
return _mm_mul_ps( _mm_set_ps1( 1.f ), *reinterpret_cast<__m128*>( f ) );
于 2016-08-25T09:01:12.113 に答える
1

私が見ることができる明らかな問題は、エイリアシング(複数のポインタタイプによるメモリ位置の参照)よりも、オプティマイザを混乱させる可能性があることです。エイリアシングの一般的な問題は、オプティマイザーが元のポインターを介してメモリ位置を変更していることを認識しないため、変更されていないと見なすことです。

あなたは明らかにオプティマイザーを完全に使用していないので(または正しいSSE命令を出すためにオプティマイザーに頼ることをいとわないでしょう)、おそらく大丈夫でしょう。

組み込み関数を自分で使用する場合の問題は、SSEレジスタで動作するように設計されており、メモリ位置からロードして単一の命令で処理する命令バリアントを使用できないことです。

于 2012-08-01T13:11:31.373 に答える