「ループは -1 まで回せ」
元の話題は int vs size_t problem のあたり。符号なし型の減算ループをどう書くかという話。
実は、一定数までカウントアップするよりも 0 を通り過ぎるまでカウントダウンする方が速度とコードサイズの両面で良い、ってのは最適化の定石だと思ってました。特にアセンブリレベルでは。
自分が使ってた 68000 だと、ずばり、「レジスタの値をデクリメントして -1 じゃなければジャンプ」という DBRA 命令がある (しかも速い) し、x86 でも、
loop: ... subl $1, %esi jns loop
みたいな形で、カウンタが符号なし型であっても高速なループが書けるんじゃないかと。
でもそういえば Metrowerks のコンパイラはこの最適化をしてくれなかったような気がするけど GCC (4.0.1 (Apple Inc. build 5465)) だとどうなんだろというわけで試してみた。
結論: 最適化してくれない orz
size_t i; while (i--)
while (--i != (size_t)-1)
の両者がいずれも、
movl $-1, %edi loop: ... cmpl %edi, %esi jne loop
みたいなコードになる。しかも、勢いあまって、
if (i != 0) do { --i; ... } while (i != 0);
と書いたら、0 から一定数までカウントアップするループに変換される。
movl %eax, %esi xorl %edi, %edi movl %eax, -32(%ebp) loop: decl %esi incl %edi ... cmpl %edi, -28(%ebp) jne loop
うーむ。
実行速度的な考察は、別途必要かなと思いますが、コード密度的にはもうひとがんばりしてほしい感じ。
10:21 追記: decl だとキャリーフラグ立たないから subl 使うべきと光成さんに教えてもらって直した。