[[PageNavi(NavigationList)]]
さて、ここではSSEを使用した場合と使用しない場合でのパフォーマンス差をチェックしたが、実はVisual Studioでもオプション設定を行うことでSSEを利用するコードを出力できる。Visual Studio 2005/2008ではMMX/SSE/SSE2命令を使用した最適化が、Visual Studio 2010ではAVXを使用した最適化がサポートされている。たとえばSSE2を利用する場合、「/arch:sse2」オプションを使用すればよい。実際にVisual Studio 2010でSSE2を利用するように設定して生成したアセンブラコードが次の'''リスト4'''だ。
====== リスト4 Visual Studio 2008でSSE2を利用するよう設定し生成したアセンブラコード ======
{{{
; 142 : d = 0.0;
xorps xmm0, xmm0
; 143 : for (i = 0; i 128; i++) {
xor eax, eax
npad 3
$LL3@main:
; 144 : d += a[i] * b[i];
movss xmm1, DWORD PTR _b$[esp+eax+1088]
movss xmm2, DWORD PTR _a$[esp+eax+1088]
cvtps2pd xmm1, xmm1
cvtss2sd xmm0, xmm0
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
addsd xmm1, xmm0
movss xmm2, DWORD PTR _b$[esp+eax+1092]
xorps xmm0, xmm0
cvtpd2ps xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1092]
cvtps2pd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1096]
movss xmm2, DWORD PTR _b$[esp+eax+1096]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
movss xmm2, DWORD PTR _b$[esp+eax+1100]
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1100]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
movss xmm2, DWORD PTR _b$[esp+eax+1104]
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1104]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
movss xmm2, DWORD PTR _b$[esp+eax+1108]
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1108]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
movss xmm2, DWORD PTR _b$[esp+eax+1112]
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1112]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
mulsd xmm1, xmm2
movss xmm2, DWORD PTR _b$[esp+eax+1116]
addsd xmm0, xmm1
movss xmm1, DWORD PTR _a$[esp+eax+1116]
cvtpd2ps xmm0, xmm0
cvtss2sd xmm0, xmm0
cvtps2pd xmm1, xmm1
cvtps2pd xmm2, xmm2
add eax, 32
mulsd xmm1, xmm2
addsd xmm0, xmm1
cvtpd2ps xmm0, xmm0
cmp eax, 512
jl $LL3@main
; 145 : }
; 146 :
; 147 : printf("%f\n", d);
sub esp, 8
cvtss2sd xmm0, xmm0
movsd QWORD PTR [esp], xmm0
push OFFSET $SG5712
call _printf
}}}
こちらの場合、「xmm0」~「xmm2」があることからも分かるとおり、確かにSSEを利用したコードが出力されている(太字がSSE命令)。ただし、インテル C++ Composer XE 2011で生成されたコードとは異なり、乗算/加算にはパックド命令は使用されておらず、同時に1つのデータしか処理していない。実行時間も9.800秒と、SSE2を利用しない場合よりもわずかではあるが劣る結果となった。
なお、Visual StudioではSSE/SSE2、およびインテル AVXのみがサポートされているが、インテル C++ Composer XE 2011ではSSE2/SSE3/SSSE3/SSE4.1/SSE4.2およびインテル AVXがサポートされている。インテル AVXが実装されたCPUはまだリリースされていないものの、コードの生成自体は可能だ。実際に'''リスト1'''のコードをインテル AVX対応CPU向けの設定でコンパイルして生成されたアセンブラコードが次の'''リスト5'''である。
====== リスト5 インテル AVXを使用するアセンブラコード ======
{{{
;;; d = 0.0;
;;; for (i = 0; i 128; i++) {
;;; d += a[i] * b[i];
lea eax, DWORD PTR [1184+esp]
and eax, 31
mov DWORD PTR [128+esp], edi
mov esi, eax
mov edi, edx
.B1.7:
mov ecx, esi
.B1.12:
vxorps ymm0, ymm0, ymm0
vxorpd ymm1, ymm1, ymm1
.B1.13:
vmovupd xmm2, XMMWORD PTR [136+esp+ecx*8]
vmovupd xmm5, XMMWORD PTR [168+esp+ecx*8]
vinsertf128 ymm3, ymm2, XMMWORD PTR [152+esp+ecx*8], 1
vinsertf128 ymm6, ymm5, XMMWORD PTR [184+esp+ecx*8], 1
vmulpd ymm4, ymm3, YMMWORD PTR [1184+esp+ecx*8]
vmulpd ymm7, ymm6, YMMWORD PTR [1216+esp+ecx*8]
vmovupd xmm2, XMMWORD PTR [200+esp+ecx*8]
vmovupd xmm5, XMMWORD PTR [232+esp+ecx*8]
vaddpd ymm0, ymm0, ymm4
vaddpd ymm1, ymm1, ymm7
vinsertf128 ymm3, ymm2, XMMWORD PTR [216+esp+ecx*8], 1
vinsertf128 ymm6, ymm5, XMMWORD PTR [248+esp+ecx*8], 1
vmulpd ymm4, ymm3, YMMWORD PTR [1248+esp+ecx*8]
vmulpd ymm7, ymm6, YMMWORD PTR [1280+esp+ecx*8]
vaddpd ymm0, ymm0, ymm4
vaddpd ymm1, ymm1, ymm7
add ecx, 16
cmp ecx, 128
jb .B1.13
.B1.14:
vaddpd ymm0, ymm0, ymm1
vextractf128 xmm1, ymm0, 1
vaddpd xmm2, xmm0, xmm1
vhaddpd xmm3, xmm2, xmm2
.B1.18:
;;; }
;;;
;;; printf("%f\n", d);
mov DWORD PTR [esp], OFFSET FLAT: ??_C@_03A@?$CFf?6?$AA@
vmovsd QWORD PTR [4+esp], xmm3
vzeroupper
call _printf
}}}
アセンブラ中で「v」で始まる命令(リスト中太字の部分)がインテル AVX命令、「ymm0」~「ymm7」はインテル AVXで新たに追加された256ビット長のYMMレジスタである。現在ではAVX対応CPUがないためパフォーマンスは測定できないが、AVX命令を駆使したコードが出力されていることは確認できる。
{{{ html
<div class="column">
}}}
==== GCCで出力されたアセンブラコード ====
Linux/Windows環境で広く使われているコンパイラの1つに、GCCがある。最新版のGCC(GCC 4.5.0)ではSSEサポートが行われており、たとえば「-march=core2 -msse4 -mfpmath=sse」といったオプションを指定することで、SSEを使用するコードを出力できる。たとえば次の'''リストA'''は、'''リスト1'''のコードを上記のオプション付きでGCCでコンパイルして生成したアセンブラコードである。
このコードではxmm0、xmm1レジスタや「movss」「「mulss」「addss」といったSSE命令が使用されていることが分かる。ただし、こちらもVisual Studioの例と同じくパックド命令は使用されておらず、インテル C++ Composer XE 2011のようなベクトル化は行われていない。
====== リストA GCCでSSEを使用するよう設定して出力したアセンブラコード ======
{{{
L26:
movl $0x00000000, %eax
movl %eax, 1560(%esp)
movl $0, 1564(%esp)
jmp L24
L25:
movl 1564(%esp), %eax
movss 1044(%esp,%eax,4), %xmm1
movl 1564(%esp), %eax
movss 532(%esp,%eax,4), %xmm0
mulss %xmm1, %xmm0
movss 1560(%esp), %xmm1
addss %xmm1, %xmm0
movss %xmm0, 1560(%esp)
incl 1564(%esp)
L24:
cmpl $127, 1564(%esp)
setle %al
testb %al, %al
jne L25
cvtss2sd 1560(%esp), %xmm0
movsd %xmm0, 4(%esp)
movl $LC1, (%esp)
call _printf
incl 1556(%esp)
L23:
cmpl $999999, 1556(%esp)
setle %al
testb %al, %al
jne L26
movl $0, %eax
leave
}}}
{{{ html
</div>
}}}
[[PageNavi(NavigationList)]]