開発メモ : __uint64のこと

x86環境ではVisual Studio 2008 の u64(← __uint64のこと)に関する最適化がとてもひどいことになる。


レジスタ割り当てが阻害されるというレベルを通り越している。


u64に対するシフトは勝手に組み込み関数を呼び出すcall命令に変換されたり、u64の下位32bitにしかbitwise orをとっていないことが明らかでも上位32bitともbitwise orをとるコードが生成されたり。ある意味バグっていると言っても良い。

こう書いてたので、
		if(SorE==ENEMY) hashVal |= (uint64)1;//下位1bitに手番を設定する
		else hashVal &= (uint64)(~1);//下位1bitに手番を設定する

		if(SorE==ENEMY) BanHash |= (uint64)1;//下位1bitに手番を設定する
		else BanHash &= (uint64)(~1);//下位1bitに手番を設定する
こう書き直したら、
		if(SorE==ENEMY)
		{
			hashVal |= (uint64)1;//下位1bitに手番を設定する
			BanHash |= (uint64)1;//下位1bitに手番を設定する
		}
		else
		{
			hashVal &= (uint64)(~1);//下位1bitに手番を設定する
			BanHash &= (uint64)(~1);//下位1bitに手番を設定する
		}
なんと遅くなります(^^;


遅くなるのがよく判らない例 ( 小宮日記 )
http://d.hatena.ne.jp/mkomiya/20091122/1258847579

実は、それは、uint64を使っているから生成されるコードがおかしくなったのだと思う。ひとことで言えばVC++がバグっているのだ。まあ正しく動作しないコードを生成するわけではないのでバグと呼ぶには適切ではないかも知れないが、本当にひどいコードが生成される。


上のコードでは 1と '|='している部分は、上位32bitは0だからhashValの上位32bit(上位32bitを表現するレジスタ)とbitwise orをとる必要はないが、VC++では、わざわざ0をレジスタに入れて、hashValの上位32bitを表現しているレジスタとbitwise orをとるコードを生成することがある。再現性が100%あるわけではない。私にはどういう条件でそのようなコードになってしまうのか正確な条件はよくわからないが、前後のcontextに影響されるのかも知れない。


ともかく、その生成されたコードはありえない。直前で0を入れてそのレジスタとbitwise orをとるだなんて、普通、コード生成の出力段の初歩的な最適化で削除されるべきコードだ。


何故こんなことになっているのかは知らないが、u64が特殊な組み込み型として扱われていてどうも最適化が阻害されるようだ。「もうx86みたいに亡びるべき環境向けの最適化なんかやってられっか!」ということなのかも知れない。


そんなわけで、u64を多用したコードはx86環境でテストしても速度面では何の参考にもならないばかりか、(部分的には)x64環境で動かすのに比べると何倍も遅い実行結果になることがある。