chibicc compiler を6800向けに改造する (9) IEEE754 float の比較(3)

BASICMASTER, 昔のパソコン

chibicc 6800のfloatの比較では、TOS (top of stack)に左辺を積んで、右辺を@longに置いて、jsr __cmpf32tos する。

cmpf32tos は AccB とフラグで比較の結果を返す。

両辺のどちらかが NaNの場合は、C=1 を返す。これは、浮動小数点数の比較演算では NaNがあれば常に不成立 であるから。

普通に考えれば if ( (a==b) || (a!=b) ) は常に成立するように見えるが、floatのときはどちらも偽になることがある。



cmpf32の返り値

条件成立時
<AccAB=$ffff
==AccAB=0
>AccAB=1

さて、帰ってきた情報を元に、どのように分岐を組み立てるのかが問題だ。

Cの条件式と同様に、成立時は1, 不成立時は0にしたい。


EQ (==)

素直に考えれば Z=1 なのだから、beq/bneで分岐して、分岐先で1か0を読めば良い。

良いのだけど、無駄が多い。9バイトも使っているし、遅い。


	jsr	cmpf32tos
	beq	L1
	clra
	clrb
	bra	L2
L1:	ldab	#1
	clra
L2:



AccBが0のときだけ Bを1にするのだから、1を引いたキャリーを使えば良い。6バイト8サイクル。最後の andb でZが変化するので、分岐にも使える。


	clra
	subb	#1
	rolb
	andb	#1



書いていて気がついたけど、こっちが1バイト短い。1も$FFもbit0が立っていることを利用する。バイト6サイクル。

eorb の代わりに addb でも良いけど、eorb の方がわかりやすいと思う。


	clra
	eorb	#1
	andb	#1


NE (!=)

AccBが0のときは、そのまま、1と$FFのときは1にしたいのだから、これで良い。超簡単。


	clra
	andb	#1


LT (<)

AccBが$FFのときは、AccB=1, それ以外は0である。 1を足すと、$FF だけキャリーが立つことを利用する。


	clra
	addb	#1
	rolb
	andb	#1



記事を書いていると、いろいろと思いつく。0と1は2で割れば0。$FFは$7Fで、最下位ビットが立つので、これで良い。2バイト短くなった。


	clra
	lsrb
	andb	#1


GT (>)

AccBが1のときだけ、AccBを1にしたい。0と$FFのときは0だ。分岐を書いて良ければ簡単。8バイト。分岐時10クロック、非分岐時12クロック。


	clra
	cmpb	#1
	beq	L1
	clrb
L1:	andb	#1



ちょっと難しいが、0から1を引くと0のときだけキャリーが立つことを利用する。ひとつずらすためにdecbを使う。7バイト、10クロック。


	clra
	decb
	subb	#1
	rolb
	andb	#1



まだ短くできた。

1を足して、$FF,0,1 を 0,1,2 にしてから1ビット右シフトすると 0,0,1 になる。最後のandも要らない。


	clra
	incb
	lsrb


LE (<=)

$FF,0 のときだけ1にしたい。1を引いて $FE,$FF,$00 にしてから2を足すと 成立時だけ C=1 になる。


	clra
	decb
	addb	#2
	rolb
	andb	#1

FE,FF,00 だと前2者だけbit7が立っていることが利用できることに気がついた。1バイト短くなった。


	clra
	decb
	aslb
	rolb
	andb	#1


GE (>=)

0,1 のときだけ1にしたい。2を引けばOK


	clra
	subb	#2
	rolb
	andb	#1