4

それぞれのサイズが 2の type の 2 つの配列で表される 2 つのベクトルがあるとdoubleします。対応する位置を追加したいと思います。ですから、ベクトルi0とを仮定して、とi1を足し合わせたいと思います。i0[0] + i1[0]i0[1] + i1[1]

タイプがdoubleであるため、2 つのレジスタが必要になります。トリックは、 i0[0]and i1[0]、 and i0[1]andi1[1]を別のものに入れ、レジスタをそれ自体に追加することです。

私の質問は、私が呼び出し_mm_load_ps(i0[0])てからを呼び出した場合_mm_load_ps(i1[0])、それらを下位と上位の 64 ビットに別々に配置するか、それともレジスタを 2 番目に置き換えるかということloadです。後で呼び出すことができるように、両方の double を同じレジスタに配置するにはどうすればよいadd_psですか?

ありがとう、

4

2 に答える 2

8

あなたが望むのはこれだと思います:

double i0[2];
double i1[2];

__m128d x1 = _mm_load_pd(i0);
__m128d x2 = _mm_load_pd(i1);
__m128d sum = _mm_add_pd(x1, x2);
// do whatever you want to with "sum" now

を実行する_mm_load_pdと、最初の double がレジスタの下位 64 ビットに配置され、2 番目の double が上位 64 ビットに配置されます。したがって、上記のロードの後、 はと(および も同様) の 2 つの値をx1保持します。への呼び出しは、およびの対応する要素を垂直方向に追加するため、追加後、下位 64 ビットと上位 64 ビットが保持されます。doublei0[0]i0[1]x2_mm_add_pdx1x2sumi0[0] + i1[0]i0[1] + i1[1]

編集:_mm_load_pdの代わりに使用する利点がないことを指摘する必要があり_mm_load_psます。関数名が示すように、このバージョンpdは 2 つのパックド double を明示的にロードし、psバージョンは 4 つのパックド単精度浮動小数点数をロードします。これらは純粋にビット単位のメモリ移動であり、どちらも SSE 浮動小数点ユニットを使用するため、データ_mm_load_psのロードに使用してもペナルティはありません。doubleまた、 には利点があり_mm_load_psます。その命令エンコーディングは よりも 1 バイト短い_mm_load_pdため、命令キャッシュの意味からより効率的です (また、命令のデコードも可能です。私は最新の x86 プロセッサのすべての複雑さの専門家ではありません)。上記のコードを使用_mm_load_psすると、次のようになります。

double i0[2];
double i1[2];

__m128d x1 = (__m128d) _mm_load_ps((float *) i0);
__m128d x2 = (__m128d) _mm_load_ps((float *) i1);
__m128d sum = _mm_add_pd(x1, x2);
// do whatever you want to with "sum" now

キャストによって暗示される機能はありません。コンパイラが SSE レジスタの内容を float ではなく double を保持するものとして再解釈し、倍精度算術関数に渡すことができるようにするだけ_mm_add_pdです。

于 2012-02-13T03:34:00.150 に答える
3

_psプレフィックスは"packed single"の省略形で、倍精度ではなく単精度浮動小数点で使用することを意味します。

代わりに、必要です_mm_load_pd()。この関数は、2 つの の配列の最初のメンバーへの 16 バイトでアラインされたポインターを取り、double両方をロードします。したがって、これを次のように使用します。

__m128d v0 = _mm_load_pd(i0);
__m128d v1 = _mm_load_pd(i1);

v0 = _mm_add_pd(v0, v1);
于 2012-02-13T03:37:59.480 に答える