Re: xor cx, cx
In article news:e11nd7$udn$1@bluegill.lbm.go.jp
toda@lbm.go.jp wrote:
> In article <e0usk3$11nc$1@nntp.tiki.ne.jp> hyama@mx7.tiki.ne.jp writes:
> 「検査」が目的だったら、andではなくtestを使うのが常道では?
and 命令の影響を考察してみましたが、なんだか手段と目的が
逆転してたような感じですね。(^^ゞ
> ・自分自身でなく他者(他レジスタ・即値・メモリ値)で検査する場合と
> ニーモニックが同一になって、意味を理解しやすくなり、
> ニーモニック誤記によるバグが防げる
8ビット機でもマクロアセンブラでよくやりました。
clr r { xor r,r } とか、
test r { and r,r }
> ・結果をレジスタに書き戻そうとしない分、速くなる可能性がある
> という利点があります。
測ってみました。
# 単一命令の繰り返しなので、実際の傾向を反映してないかも知れません。
6621C9 and %cx,%cx // 2.410
21C9 and %ecx,%ecx // 2.410
6685C9 test %cx,%cx // 1.109
85C9 test %ecx,%ecx // 0.965
2.5倍も早かったです。
6631C9 xor %cx,%cx // 2.410
66B90000 mov $0,%cx // 2.410
6629C9 sub %cx,%cx // 2.410
31C9 xor %ecx,%ecx // 0.965
B900000000 mov $0,%ecx // 1.061
29C9 sub %ecx,%ecx // 0.964
こっちは、コードサイズの割には一割ほど。
6683F9FF cmp $-1,%cx // 0.836
83F9FF cmp $-1,%ecx // 1.109
6641 inc %cx // 2.410
41 inc %ecx // 2.410
コードサイズのと実行速度が逆転してます。
なぜか、cmp ecx より cmp cx の方が早い。
> もちろん、そもそもtestという命令が無いcpuだと話は別ですが。
今回の場合 x86 が本題でしたから、元祖 8086 からある test命令を
使った方が正しいと思います。
ついでなので、閏年の判定関数を二つ作って
遊んで^H^H^H速度比較してみました。
int leap_asm( unsigned int y ){
__asm(
"movl 8(%ebp), %edx" "\n\t" // y
"xor %eax, %eax" "\n\t"
"test $3, %dl" "\n\t"
"jnz ret_ax" "\n\t"
"xchg %eax, %edx" "\n\t" // eax==0, edx<->eax
"mov $100, %cx" "\n\t"
"div %cx" "\n\t"
"test %dx, %dx" "\n\t"
"jnz ret_1" "\n\t"
"xchg %eax, %edx" "\n\t" // edx == 0
"test $3, %dl" "\n\t"
"jnz ret_ax" "\n\t"
"ret_1:" "\n\t"
"mov $1, %eax" "\n\t"
"ret_ax:" "\n\t"
);
}
int leap_asm2( unsigned int y ){
__asm(
"movl 8(%ebp), %edx" "\n\t" // y
"xor %eax, %eax" "\n\t"
"test $3, %dl" "\n\t"
"jnz ret_ax" "\n\t"
"mov $400, %cx" "\n\t" // y = 1583 .. 4000
".p2align 2,,3" "\n\t"
"leap_400:" "\n\t"
"sub %cx, %dx" "\n\t"
"jnc leap_400" "\n\t"
// "jz ret_1" "\n\t"
"mov $100, %cx" "\n\t" // sar $2,%cx
"add %cx, %dx" "\n\t"
"jz ret_ax" "\n\t"
"add %cx, %dx" "\n\t"
"jz ret_ax" "\n\t"
"add %cx, %dx" "\n\t"
"jz ret_ax" "\n\t"
//"ret_1:" "\n\t"
"mov $1, %eax" "\n\t"
"ret_ax:" "\n\t"
);
}
int leap_std( unsigned y )
{
return( y % 4 == 0 && y % 100 != 0 || y % 400 == 0 );
}
前者が div ありで、後者が減算ループです、
グレゴリオ暦の閏年処理なので検査は、1583..3000までにしました。
leap_asm 1.385
leap_asm2 1.286
leap_std 4.762
四分の三は同じ処理なので、ほとんど差が出ませんね。(^^;
# 8,16bit CPU の感覚で書いているので、
# 調整すべきところがあると思います。(--;
--
山口@福岡 <hyama@mx7.tiki.ne.jp>
Fnews-brouse 1.9(20180406) -- by Mizuno, MWE <mwe@ccsf.jp>
GnuPG Key ID = ECC8A735
GnuPG Key fingerprint = 9BE6 B9E9 55A5 A499 CD51 946E 9BDC 7870 ECC8 A735