MinGWとSSEとイントリンシック
イントリンシック関係メモ。 -O2最適化前提。
○宣言&初期値指定は構造体みたい出来る。 但し、intに対して4要素指定は出来ない?(warning)
ok: __m128d xmm={ n,n }; __m128 xmm={ n,n,n,n }; __m128i xmm={ n,n };
ng: __m128i xmm={ n,n,n,n };
実際にxmmが使われる時に妥当な命令(movXX xmm, n)にして適用される。
xmm = _mm_set_pd( n )等で指定するのと変わらない。
○loadも同時にこなせる命令へのデータの渡し方(指定方法)。
mulXXやaddXX命令自体はソースにメモリアドレス指定を受けられる。
mulpd xmm, oword ptr [eax]、addpd (%eax), %xmm等。
でも、イントリンシックのマクロに対して、_mm_mul_pd(xmm, ptr);としても受け付けない。
その場合、妥当な型にキャストする事で渡す事が出来る。
_mm_mul_pd(xmm, *(__m128d*)ptr); _mm_movedup_pd(*(__m128d*)&dval);等。
但し、ptrの指す先が16バイトアラインにある事を要求する物もあるので注意が必要(インテルのドキュメント参照)。
また、キャストによってアドレスの加減算量が128bit系に変わるので注意。
(__m128d*)&dval +1; == (__128d*)(&dval +2); 等。
int*2>double*2の変換 _mm_cvtepi32_pd()は _mm_loadu_si128()でxmmにloadしてからの方が速いっぽい。
前後に重い命令があれば隠蔽されるかもしれないけど、変換してから計算を始めるような場合は速度差が出やすい気がする。
最適化で_mm_mul_sd(xmm, *(p))が、movapd %p %xmmとmulsd~となる、何をしたいのか解らない挙動が結構頻発する気がする。
当然、pが16byteアラインになければ落ちる(゚Д゚)
○xmmを関数を跨いで参照する時、勝手にxmmをスタックにstore/loadする可能性がある。
{
aligned var;
__m128d xmm;
{ xmm... } xmmを使った作業。
{ var=xmm } xmmをvarにstore※。
func() 関数。xmmを破壊し得る。
{ xmm = var } xmmへvarをload※。
{ xmm... } xmmを使った作業。
}
として、func()が同一モジュール内(非static/非inline)に有る場合、varへのstore/loadとは別に、何処かに対して"movaps"を用いてxmmを退避させる。
その為、本体関数のフレームポインタ(スタックポインタ?)が16バイトアラインに無い場合、エラーになる。
本体関数の上流関数を __attribute__((force_align_arg_pointer)) としていても4バイトアラインで強行されるっぽい。
本体関数を明示的に force_align_arg_pointer する事で回避出来る。
面倒なら、コンパイルオプション -mstackrealign を付けておくのもありかもしれない(全関数が冗長になるけど)。
※のstore/loadを省いても(varを省いても)、上記のようにxmmの内容が保持される。
varをvarとして扱う事が無い場合、省く事で無意味なstore/loadを減らせる。
MinGW4.2(位)以下には、force_align~もオプションも無いので注意('д`)
あ、未テストだけど、xmmにalignedを付けて見るのはどうだろう。(意味有りませんでしたw)
○宣言&初期値指定は構造体みたい出来る。 但し、intに対して4要素指定は出来ない?(warning)
ok: __m128d xmm={ n,n }; __m128 xmm={ n,n,n,n }; __m128i xmm={ n,n };
ng: __m128i xmm={ n,n,n,n };
実際にxmmが使われる時に妥当な命令(movXX xmm, n)にして適用される。
xmm = _mm_set_pd( n )等で指定するのと変わらない。
○loadも同時にこなせる命令へのデータの渡し方(指定方法)。
mulXXやaddXX命令自体はソースにメモリアドレス指定を受けられる。
mulpd xmm, oword ptr [eax]、addpd (%eax), %xmm等。
でも、イントリンシックのマクロに対して、_mm_mul_pd(xmm, ptr);としても受け付けない。
その場合、妥当な型にキャストする事で渡す事が出来る。
_mm_mul_pd(xmm, *(__m128d*)ptr); _mm_movedup_pd(*(__m128d*)&dval);等。
但し、ptrの指す先が16バイトアラインにある事を要求する物もあるので注意が必要(インテルのドキュメント参照)。
また、キャストによってアドレスの加減算量が128bit系に変わるので注意。
(__m128d*)&dval +1; == (__128d*)(&dval +2); 等。
int*2>double*2の変換 _mm_cvtepi32_pd()は _mm_loadu_si128()でxmmにloadしてからの方が速いっぽい。
前後に重い命令があれば隠蔽されるかもしれないけど、変換してから計算を始めるような場合は速度差が出やすい気がする。
最適化で_mm_mul_sd(xmm, *(p))が、movapd %p %xmmとmulsd~となる、何をしたいのか解らない挙動が結構頻発する気がする。
当然、pが16byteアラインになければ落ちる(゚Д゚)
○xmmを関数を跨いで参照する時、勝手にxmmをスタックにstore/loadする可能性がある。
{
aligned var;
__m128d xmm;
{ xmm... } xmmを使った作業。
{ var=xmm } xmmをvarにstore※。
func() 関数。xmmを破壊し得る。
{ xmm = var } xmmへvarをload※。
{ xmm... } xmmを使った作業。
}
として、func()が同一モジュール内(非static/非inline)に有る場合、varへのstore/loadとは別に、何処かに対して"movaps"を用いてxmmを退避させる。
その為、本体関数のフレームポインタ(スタックポインタ?)が16バイトアラインに無い場合、エラーになる。
本体関数の上流関数を __attribute__((force_align_arg_pointer)) としていても4バイトアラインで強行されるっぽい。
本体関数を明示的に force_align_arg_pointer する事で回避出来る。
面倒なら、コンパイルオプション -mstackrealign を付けておくのもありかもしれない(全関数が冗長になるけど)。
※のstore/loadを省いても(varを省いても)、上記のようにxmmの内容が保持される。
varをvarとして扱う事が無い場合、省く事で無意味なstore/loadを減らせる。
MinGW4.2(位)以下には、force_align~もオプションも無いので注意('д`)
あ、未テストだけど、xmmにalignedを付けて見るのはどうだろう。(意味有りませんでしたw)
この記事へのコメント