MMXなんて実際に使ったことなんてないんだけど
GCCの内部もなーんとなくわかってきたところで、GCCでMMX使うのもなんとなくわかってきた。
/* * typedef ... hoge __attribute__ ((mode(V4SI)))でGCC拡張型でtypedefできる。 * 下ではintってなってるけど、intは多分無視される。floatでもlongでも関係無い。 * * * modeっていうのは GCCの内部での型の名前みたいなもの * V4SI = Single Integer 4個 の Vector */ typedef int v4si __attribute__ ((mode(V4SI))); /* Single Float 4個分 */ typedef int v4sf __attribute__ ((mode(V4SF))); /* Double Float 2個分 */ typedef int v2df __attribute__ ((mode(V2DF))); /* Quarter Integer 8個分 */ typedef int v8qi __attribute__ ((mode(V8QI))); typedef unsigned char uchar; void vqadds( uchar *x, uchar *y, uchar *z, int elem_num ) { v8qi *vx = (v8qi*)x; v8qi *vy = (v8qi*)y; v8qi *vz = (v8qi*)z; int i; for ( i=0; i<(elem_num/8); i++ ) { vx[i] = vy[i] + vz[i]; } }
これで、8バイト同時加算ができるはず。おもいっきりGCC拡張なんだけど。
よーするに、「こいつはベクトル型ですよー」っていう型を作っといて、そいつにキャストする、と。unionでそーいうのを作っちゃってもいいか。で、ベクトル型同士で演算を行うと、それに対応するベクトル命令が生成される、という感じだ。
自分でベクトル指定しないといけないんだったら生asm書いたのとあんまり変わらないような気もするんだけど、生asmを使う場合よりもいいのは、
と、いう感じで、2番目は大きいんじゃないかと。
あと、機種依存しちゃうんだけど、__buitin_ia32_paddusbみたいなのを使えば、対応する命令を吐かせるのもできる。ia32命令については、gcc.infoのC Extensionのところ。
Adasさんのところに-mfpmath=sseで4倍速くなるんじゃないかって書いてあるだけど、-msseは「sse使ってもいい」で-mfpmath=sseが「浮動小数点演算にsse命令を使う」っていう意味しか無くて、Vectorizeまでは面倒見てくれないので、オプション付けるだけではsse命令が出たとしても387で計算するのとあんまり変わらないかと。
と、思わせておいて、gcc-4.0ではアラインメントを保証してやれば自動でやってくれる。
typedef float afloat __attribute__((__aligned__(16))); /* __restrict__ は「この変数の中身は勝手に変わらない」ぐらいの意味でいいのか? よくわからん。 * とりあえず必要…らしい */ void add_fvec( afloat * __restrict__ x, afloat *__restrict__ y, afloat * __restrict__ z ) { int i; for ( i=0; i<256; i++ ) { x[i] = y[i] + z[i]; } }
で、
$ gcc -ftree-vectorize -O2 -S -mfpmath=sse -msse2 sse.c
こんな感じで。まあ、まだちょっと、「GCCは偉いなぁ…」って感動するためだけの観賞用って感じもするけど。
参考: http://gcc.gnu.org/projects/tree-ssa/vectorization.html