後で見ると当たり前なんだけど、少し工夫した部分を書いていきたい。話題になってたし。
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倍越えたかなーというギリギリのところなのが救いか…他にも書いていくとミスに気付きそうだなぁ。