遅いビットスワップかも

前に乗算・除算用のアセンブラコードの話を紹介した。

マイコンのわり算事情

ちょっと古いマイコンで直接的な除算命令がなく、1bit単位の処理を繰り返す方法で実現されていたと。


もう1つ、アセンブラで作られていたのがビットスワップ処理である。

ビットスワップとは上位ビットと下位ビットを入れ替えることである。

例えば、0x89AB は2進数で表すと 10001001 10101011 となるが、

ビットスワップは2進数を逆順に並べて 11010101 10010001 とした 0xD591 とする処理である。

しばしばこのようなビット順を入れ替える処理というのが必要になることがある。


このような処理を一般的な演算命令でやる場合はこうなる。

ビット順を入れ替えたかった

とはいえ、このような処理を行う専用の命令を持っているCPUも多く……

ARMだと REV命令 でバイト順を反転でき、RBIT命令でビット順を反転できる。x86だと BSWAP命令 でバイト順を反転できる。

そういう処理ですね。


でも、このマイコンにはそのような処理はなく、論理演算の組み合わせで作っているわけでもなく、

どうやったかというとローテート命令を繰り返す方法で実現している。

ローテート命令はビットシフトに似ているのだが、

左ローテートだと上位ビットから押し出されたビットを下位ビットに戻す処理がある。

1ワードであれば上位ビットを下位ビットに戻すだけだが、

複数ワードにまたがってやることもあろうと、フラグビットに押し出して、フラグビットに補充するという命令もある。

レジスタAの上位ビットをフラグビットに押し出して、

レジスタBの上位ビットに押し込んで、下位ビットをフラグビットに押し出して、

レジスタAの下位ビットに押し込んで、上位ビットをフラグビットに押し出して……

という処理を繰り返すと、レジスタAの最上位ビットはBの最下位ビットにたどり着き、

逆にレジスタBの最下位ビットはAの最上位ビットにたどり着く。

これによりレジスタAとB、それぞれのビットスワップした値がBとAに入るというわけ。


ただ、この処理、意外と時間がかかるんですね。

除算処理が遅いのはそうだろうと思ったけど、それとほぼ同じである。

理由はローテート命令を多く繰り返す必要があるから。

ほとんど構造が除算命令と同じなんですね。

論理演算の方が早いのでは? と思ったけど、実際どうなんだろ?

論理演算で効率的にやるには定数が様々必要になる、

そういうデータをロードするのにかかる時間に比べれば速いかもしれないが、

一方で一旦ロードしてしまえば繰り返し使えるので、

大量のデータをスワップし続けるなら明らかに早そうである。


当時色々検討した上でこういう形になっているのだろうから、

おそらく効率的なのだろうけど、思ったより分が悪いなとは思った。