cntb

後で見ると当たり前なんだけど、少し工夫した部分を書いていきたい。話題になってたし。

http://pc11.2ch.net/test/read.cgi/tech/1232817361/371-

私は基本的には、 y を bit ごとの tempering 後の値、 r は任意レジスタ、 0 は 0 の入ってるレジスタ、 s を bit ごとに作っている sum 、として、

cntb $r, $r, $y
sumb $r, $r, $0
a    $s, $s, $r

みたいな感じでやりました。こうやって bit ごとに集計しておけば後は、

int sum = 0;
for (a = 0; a < 32; a++) {
  sum += s[a] << a;
}

的な方法で合計値は取り出せる、というのが基本的な話。これだとこの処理に bit ごとにループ内で 32*3 = 96 命令かかることになる。もうちょい減らせるよねーということで、微妙に工夫しました。最適かどうかは知らないけど。

まず 31bit 目の値。これってのはどうせ <<31 とか最後にしちゃうので、偶奇だけ残ってればいい。偶奇だけ残ってりゃいいんなら単に、

xor $s, $s, $y

を計算しておいて後で cntb => sumb すれば偶奇は一致してるはず。

同じく、 16bit 目から 30bit 目までは、最後に上 16bit は捨ててしまうので、下 16bit だけ覚えてればいい。つまり short で加算すれば良いので、

cntb $r1, $r1, $y1
cntb $r2, $r2, $y2
sumb $r, $r1, $r2
ah   $s, $s, $r

などとして、2bit ずつまとめて計算してやることができる。

ここまで書いてて凡ミスに気付いた… 25bit 目から 30bit 目まではもうすこし少ない命令で…とか書こうと思ったんだけど、どう見ても short 加算の方がクロック数少ないし何よりレジスタ数ケチれる…

ええとあまり意味はないけど、 25bit 目からは 7bit 残しとけばいいので、 cntb した後ですぐに a してしまって、オーバーフローしないようにループ中で一回だけ andi 127 かけてやるというものでした。しかしこっちの方がクロック数は多いのであった…

まぁこのへんは小さいので、ちゃんとやってりゃ100倍越えたかなーというギリギリのところなのが救いか…他にも書いていくとミスに気付きそうだなぁ。

なにかあれば下記メールアドレスへ。
shinichiro.hamaji _at_ gmail.com
shinichiro.h