鍋あり谷あり

テーマを決めずに適当に書いています。

マイクロソフトの すごい 最適化

なんか、すごい最適化をすることがあるのを発見した。
ソースは

void foo( char * );
void bar()
{
  char buf[] = {
    0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
    0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,0,1,2,3,4,5,6,7,8,9,
  };
  foo( buf );
}

こんな感じ。これを gccコンパイルして -O3 で最適化すると、データをまず定義して、bar の中ではそのデータをスタック上にある buf にコピー。普通だと思う。
これが。マイクロソフトコンパイラだと全然違う最適化になる。

コマンドライン

cl -GX -Ox -c -Fa test.cpp

こんな感じ。
折角なので、コンパイルした結果を(ほぼ)そのまま載せてしまおう:

	sub	esp, 60					; 0000003cH
	mov	al, 9
	mov	dl, 7
	mov	cl, 8
	mov	BYTE PTR _buf$[esp+69], al
	mov	BYTE PTR _buf$[esp+79], al
	mov	BYTE PTR _buf$[esp+89], al
	mov	BYTE PTR _buf$[esp+99], al
	mov	BYTE PTR _buf$[esp+109], al
	mov	BYTE PTR _buf$[esp+119], al
	push	ebx
	mov	bl, 6
	lea	eax, DWORD PTR _buf$[esp+64]
	push	eax
	mov	BYTE PTR _buf$[esp+68], 0
	mov	BYTE PTR _buf$[esp+69], 1
	mov	BYTE PTR _buf$[esp+70], 2
	mov	BYTE PTR _buf$[esp+71], 3
	mov	BYTE PTR _buf$[esp+72], 4
	mov	BYTE PTR _buf$[esp+73], 5
	mov	BYTE PTR _buf$[esp+74], bl
	mov	BYTE PTR _buf$[esp+75], dl
	mov	BYTE PTR _buf$[esp+76], cl
	mov	BYTE PTR _buf$[esp+78], 0
	mov	BYTE PTR _buf$[esp+79], 1
	mov	BYTE PTR _buf$[esp+80], 2
	mov	BYTE PTR _buf$[esp+81], 3
	mov	BYTE PTR _buf$[esp+82], 4
	mov	BYTE PTR _buf$[esp+83], 5
	mov	BYTE PTR _buf$[esp+84], bl
	mov	BYTE PTR _buf$[esp+85], dl
	mov	BYTE PTR _buf$[esp+86], cl
	mov	BYTE PTR _buf$[esp+88], 0
	mov	BYTE PTR _buf$[esp+89], 1
	mov	BYTE PTR _buf$[esp+90], 2
	mov	BYTE PTR _buf$[esp+91], 3
	mov	BYTE PTR _buf$[esp+92], 4
	mov	BYTE PTR _buf$[esp+93], 5
	mov	BYTE PTR _buf$[esp+94], bl
	mov	BYTE PTR _buf$[esp+95], dl
	mov	BYTE PTR _buf$[esp+96], cl
	mov	BYTE PTR _buf$[esp+98], 0
	mov	BYTE PTR _buf$[esp+99], 1
	mov	BYTE PTR _buf$[esp+100], 2
	mov	BYTE PTR _buf$[esp+101], 3
	mov	BYTE PTR _buf$[esp+102], 4
	mov	BYTE PTR _buf$[esp+103], 5
	mov	BYTE PTR _buf$[esp+104], bl
	mov	BYTE PTR _buf$[esp+105], dl
	mov	BYTE PTR _buf$[esp+106], cl
	mov	BYTE PTR _buf$[esp+108], 0
	mov	BYTE PTR _buf$[esp+109], 1
	mov	BYTE PTR _buf$[esp+110], 2
	mov	BYTE PTR _buf$[esp+111], 3
	mov	BYTE PTR _buf$[esp+112], 4
	mov	BYTE PTR _buf$[esp+113], 5
	mov	BYTE PTR _buf$[esp+114], bl
	mov	BYTE PTR _buf$[esp+115], dl
	mov	BYTE PTR _buf$[esp+116], cl
	mov	BYTE PTR _buf$[esp+118], 0
	mov	BYTE PTR _buf$[esp+119], 1
	mov	BYTE PTR _buf$[esp+120], 2
	mov	BYTE PTR _buf$[esp+121], 3
	mov	BYTE PTR _buf$[esp+122], 4
	mov	BYTE PTR _buf$[esp+123], 5
	mov	BYTE PTR _buf$[esp+124], bl
	mov	BYTE PTR _buf$[esp+125], dl
	mov	BYTE PTR _buf$[esp+126], cl
	call	?foo@@YAXPAD@Z				; foo
	add	esp, 4
	pop	ebx
	add	esp, 60					; 0000003cH
	ret	0

マイクロソフトコンパイラの判断は、敢えて byte 単位で move。
レジスタは活用するかもしれないが、eax とかは使わず、敢えて al〜dl。

なんで?>マイクロソフト