toge's diary

コンピュータ関連の趣味をつらつらと。

C++レベルでの並列化

Blackswordさんのコメントより。

私のコードを見れば判ると思いますがベクトル化と同時実行を期待した並列化の2つで
速度を稼いでいます。

にひっかかって実験してみる。

最初はBlackswordさんのコードよりもってきたコード。

int test (float* data, float* data2, float* data3) {
  int i = 0;

  __m128	XMM0, XMM1, XMM2, XMM3;
  XMM0	 = PM128(&data[i   ]);
  XMM1	 = PM128(&data[i+ 4]);
  XMM2	 = PM128(&data[i+ 8]);
  XMM3	 = PM128(&data[i+12]);
  XMM0	 = _mm_mul_ps(XMM0, PM128(&data2[i   ]));
  XMM1	 = _mm_mul_ps(XMM1, PM128(&data2[i+ 4]));
  XMM2	 = _mm_mul_ps(XMM2, PM128(&data2[i+ 8]));
  XMM3	 = _mm_mul_ps(XMM3, PM128(&data2[i+12]));
  PM128(&data3[i   ])	 = XMM0;
  PM128(&data3[i+ 4])	 = XMM1;
  PM128(&data3[i+ 8])	 = XMM2;
  PM128(&data3[i+12])	 = XMM3;

  return 0;
}

でこれのgcc-4.0.0 -march=athlon-xp -O3 -Sでの結果。

test:
	pushl	%ebp
	movl	%esp, %ebp
	movl	12(%ebp), %eax
	movl	8(%ebp), %edx
	movl	16(%ebp), %ecx
	movaps	(%eax), %xmm3
	movaps	16(%eax), %xmm2
	movaps	32(%eax), %xmm1
	movaps	48(%eax), %xmm0
	mulps	(%edx), %xmm3
	xorl	%eax, %eax
	mulps	16(%edx), %xmm2
	mulps	32(%edx), %xmm1
	mulps	48(%edx), %xmm0
	movaps	%xmm3, (%ecx)
	movaps	%xmm2, 16(%ecx)
	movaps	%xmm1, 32(%ecx)
	movaps	%xmm0, 48(%ecx)
	leave
	ret

こんどは並列化を無視してみた場合。

int test (float* data, float* data2, float* data3) {
  int i = 0;

  __m128	XMM0, XMM1, XMM2, XMM3;
  XMM0	 = PM128(&data[i   ]);
  XMM0	 = _mm_mul_ps(XMM0, PM128(&data2[i   ]));
  PM128(&data3[i   ])	 = XMM0;

  XMM1	 = PM128(&data[i+ 4]);
  XMM1	 = _mm_mul_ps(XMM1, PM128(&data2[i+ 4]));
  PM128(&data3[i+ 4])	 = XMM1;

  XMM2	 = PM128(&data[i+ 8]);
  XMM2	 = _mm_mul_ps(XMM2, PM128(&data2[i+ 8]));
  PM128(&data3[i+ 8])	 = XMM2;

  XMM3	 = PM128(&data[i+12]);
  XMM3	 = _mm_mul_ps(XMM3, PM128(&data2[i+12]));
  PM128(&data3[i+12])	 = XMM3;

  return 0;
}

同じくgcc-4.0.0 -march=athlon-xp -O3 -Sでの結果。

test:
	pushl	%ebp
	movl	%esp, %ebp
	movl	12(%ebp), %eax
	movl	8(%ebp), %ecx
	movl	16(%ebp), %edx
	movaps	(%eax), %xmm0
	mulps	(%ecx), %xmm0
	movaps	%xmm0, (%edx)
	movaps	16(%eax), %xmm0
	mulps	16(%ecx), %xmm0
	movaps	%xmm0, 16(%edx)
	movaps	32(%eax), %xmm0
	mulps	32(%ecx), %xmm0
	movaps	%xmm0, 32(%edx)
	movaps	48(%eax), %xmm0
	xorl	%eax, %eax
	mulps	48(%ecx), %xmm0
	movaps	%xmm0, 48(%edx)
	leave
	ret

なるほど、並列化は自分でしないといけないのね。
xmmintrin.hで嬉しいのはレジスタの割当てぐらいなもんですか。
ということはまだまだ最適化の余地はあるなぁ。