#include #include #include "redundant.h" #define SSE2 //#define MMX //#define DEBUG // SSE2のpxor命令を用いて128bitずつXORの演算を行う void SIMD_XOR(void *src1, void *src2, void *dst, size_t size) { unsigned int long_size, op_cnt; unsigned long t; unsigned long *src_lp, *dst_lp; #ifdef SSE2 // SSE2命令を用いて128bitずつXORを計算する #ifdef DEBUG printf("SSE2 Mode.\n"); #endif op_cnt=(int)(size/16); // src1,src2,dstの3つのレジスタが必要 asm volatile ("\n" " mov %3, %%eax\n" " calc:\n" " movdqu (%1),%%xmm0\n" " movdqu (%2),%%xmm1\n" " pxor %%xmm1,%%xmm0\n" " movdqu %%xmm0,(%3)\n" " sub $1, %%eax\n" " cmp $0, %%eax\n" " je end\n" " add $16, %%esi\n" " add $16, %%edi\n" " jmp calc\n" " end:\n" " emms\n" /* MMX命令終了*/ : : "r" (src1), "r" (src2), "r" (dst), "r" (op_cnt) : "%eax" ); // " emms" :: "S" (src_p), "D" (dst_p), "r" (op_cnt) : "%eax" // rにするとレジスタを自動割り当て // 残った分を1バイトずつ計算 for(t=op_cnt*16; tUserData.data[t]; } #else #ifdef MMX // MMX命令を用いて64bitずつXORを計算する #ifdef DEBUG printf("MMX Mode.\n"); #endif op_cnt=(int)(size/8); asm volatile ("\n" " mov %2, %%eax\n" " calc:\n" " movq (%%esi),%%mm0\n" " movq (%%edi),%%mm1\n" " pxor %%mm1,%%mm0\n" " movq %%mm0,(%%edi)\n" " sub $1, %%eax\n" " cmp $0, %%eax\n" " je end\n" " add $8, %%esi\n" " add $8, %%edi\n" " jmp calc\n" " end:\n" " emms" :: "S" (src_p), "D" (dst_p), "r" (op_cnt) : "%eax" ); // 残った分を1バイトずつ計算 for(t=op_cnt*8; tdata[t]; } #else // longでXORを計算する // longの長さを取得 long_size=sizeof(long); #ifdef DEBUG printf("Size of long : %d bytes\n", long_size); #endif // pktとparityの先頭アドレスをlongのポインタに変換 src_lp=(unsigned long *)src_p; dst_lp=(unsigned long *)dst_p; // longの単位でXORを計算 op_cnt=(int)(UserDataSize/long_size); for(t=0;tUserData.data[t]; } #endif #endif } /* アセンブラコード解説 ・MMX asm volatile (" mov %2, %%eax // op_cntをEAXに代入 calc: movq (%%esi),%%mm0 // src_lpから64bit分のデータをMM0に転送(MMX命令) movq (%%edi),%%mm1 // dst_lpから64bit分のデータをMM1に転送(MMX命令) pxor %%mm1,%%mm0 // MM1とMM0のXORを計算する。結果はMM0。(MMX命令) movq %%mm0,(%%edi) // MM0の内容をEDI(dst_lp)に転送 (MMX命令) sub $1, %%eax // EAXから1を引く cmp $0, %%eax // EAXと0を比較して、同じならEFLAG?がONになる je end // EFLAGがONならばendにジャンプ add $8, %%esi // ESIのアドレス値に8を加算する add $8, %%edi // EDIのアドレス値に8を加算する jmp calc // calcにジャンプ end: emms" :: "S" (src_p), "D" (dst_p), "r" (op_cnt) : "%eax" ); ・SSE2 MMXとほとんど同じ。MMXレジスタ(mm0..mm7)の代わりに、 SSEレジスタ(xmm0..xmm7)を使う。pxorは、指定したレジスタによって 自動的に64bitか128bitかを判別して計算するらしい。 asm volatile (" mov %2, %%eax calc: movdqu (%%esi),%%xmm0 // データを128bit移動。 movdqu (%%edi),%%xmm1 pxor %%xmm1,%%xmm0 // SSEレジスタのXORを計算 movdqu %%xmm0,(%%edi) sub $1, %%eax cmp $0, %%eax je end add $16, %%esi // 16bytes(128bit)分アドレスを加算 add $16, %%edi jmp calc end: emms" :: "S" (src_p), "D" (dst_p), "r" (op_cnt) : "%eax" ); ・MMXテスト結果 30000bytesのXORを200万回計算したところ、 SSE2(128bit): 10秒 MMX(64bit) : 66秒 long(32bit) : 146秒 という結果が得られた。 */