- ベストアンサー
インラインアセンブラでの配列要素の加算について
- インラインアセンブラを使ってunsigned char型の配列の要素を加算するプログラムが正常に動作しない問題が発生しています。
- 配列ansに正しい解が代入されず、全ての要素が205になってしまいます。
- 問題の原因が特定できず、質問者は自力で問題点を見つけることができません。ご指摘をお願いします。
- みんなの回答 (3)
- 専門家の回答
質問者が選んだベストアンサー
★アドバイス >MovQ mm0, [eax][ecx * 8] ↑ [ecx * 8]がオフセットになります。 この記述を使えば max = (LEN / 8) - 1; _asm { mov ecx, max mov eax, t0 mov esi, t1 mov edi, t2 LOOPSTART: movq mm1, [esi][ecx * 8] movq mm2, [edi][ecx * 8] paddb mm1, mm2 movq [eax][ecx * 8],mm1 dec ecx jns LOOPSTART emms } と記述できますね。
その他の回答 (2)
- Oh-Orange
- ベストアンサー率63% (854/1345)
★追記。 ・ソースを良く見たらレジスタへのセットがおかしいようです。 ans、src1、src2 のポインタを普通のレジスタにセットしてから movq で mm0、mm1、mm2 レジスタにセットします。 下に全ソースを貼り付けて置きます。 #include <stdio.h> #include <stdlib.h> #define LEN (64) // メイン関数 int main( void ) { unsigned char *ans, *src1, *src2; unsigned char *t0, *t1, *t2; int i, max; t0 = ans = (unsigned char *)malloc( sizeof(unsigned char) * LEN ); t1 = src1 = (unsigned char *)malloc( sizeof(unsigned char) * LEN ); t2 = src2 = (unsigned char *)malloc( sizeof(unsigned char) * LEN ); // 配列ans、src1、src2の初期化 for ( i = 0 ; i < LEN ; i++ ){ ans[ i ] = (unsigned char)(0); src1[ i ] = (unsigned char)(i + 0); src2[ i ] = (unsigned char)(i + 1); } max = (LEN / 8); _asm { mov ecx, max LOOPSTART: // レジスタへの代入 mov eax, t0 mov esi, t1 mov edi, t2 // MMX演算 movq mm1, [esi] movq mm2, [edi] paddb mm1, mm2 movq [eax],mm1 // ポインタの加算 add t0, 8 add t1, 8 add t2, 8 loop LOOPSTART emms } for ( i = 0 ; i < LEN ; i++ ){ printf( "%2d + %2d = %2d\n", src1[i], src2[i], ans[i] ); } return 0; }
- Oh-Orange
- ベストアンサー率63% (854/1345)
★アドバイス >高速化を目指しMMXを使用しているのですが、うまく動作しません。 ↑ paddusb命令は飽和演算を行います。 多倍長演算には利用できないと思います。 つまり加算・減算において 255 以上なら 255 になるためキャリーとして 次の配列に演算を行わないため上手く動作しなくても正常だと思います。 ・下に参考ページを載せておきますので MMX の paddusb 命令について もう一度動作の確認をして下さい。 なお、使うなら paddb 命令の方ではないでしょうか? こちらならバイト区切りのオーバーフローとキャリーありで加算を行います。 参考ページ: http://hp.vector.co.jp/authors/VA014520/asmhsp/chap8.html→『MMX命令による画像処理』 http://www7b.biglobe.ne.jp/robe/pf/pf009.html→『第九報:MMX 最適化』 http://www9.ocn.ne.jp/~mkisa/asm.htm→『インラインアセンブリ』
お礼
Oh-Orange様、返信ありがとうございました。 適切な回答と、参考ページまで紹介いただき、とても感謝しています。 おっしゃる通り、ポインタをレジスタに一度格納しておかなければなりませんでした。 結果、正常に動作するようプログラムを組むことが出来ました。 ありがとうございました。 最後にひとつ気になったことがあるのですが、 ご紹介にいただいた2番目の参考ページについてです。 アセンブラ部分を見ると MovQ mm0, [eax][ecx * 8] このような表記があります。 ソースオペランドに引数を2つもっているのですが、これはどのような意味なのでしょう?