2007-03-11 (日)
*avr-gccメモ
なんか,gccがすごく気に食わないコードを生成するのですが,コンパイルオプションが悪いのかなぁ….
到達不可能な場所から呼ばれている関数が残ることがある
到達不可能なコードは最適化時に消してくれますが,そこから呼ばれている関数が残ってしまうことがあります.関数にstaticが付いていても,安心できません.
scrc,scrs命令を意識
AVRには,特定のビットを見て一命令スキップする便利な命令があります.avr-gccはif文の中身が一命令で済み,条件を左右するのが1ビットのみな場合,scrs命令を使ってくれるようです.
a が 0 か 1 の場合は a!=0 として判定するよりも, a&1 で判定しましょう.
整数リテラルをintとして扱う
255以下の整数はunsigned charとして扱って欲しいところ.具体的には,aがchar型だったとして「a&0x22」とかを計算すると,andi命令は副作用があるので,aを別レジスタにコピーする.そのときに,16ビットに拡張してから0x22とのandiを取ろうとすることがあるようです.
if (a&0x22) { // ... } uint8_t tmp=0x22; if (a&tmp) { // ... }
上のより下の方がコードサイズが小さくなることがある.
リテラルをキャストしても無効っぽいので,「inline static uint8_t byte(uint8_t t) {return t;}」という関数を作ってしまう手もある.C言語の整数のサフィックスになんでchar型に相当するものが無いんでしょうか.
シフトには気をつける
AVRには任意ビットのシフト命令がありません.シフトで変なコードが生成されやすいです.
8ビットシフトは,バイトごとの移動でやってくれますが,算術シフトだと,符号のための分岐命令が出てきたりします.
「||」はなるべく避ける
「||」の左右の式の間の最適化は殆どされないようです.評価順序がどうでも良い場合は,「|」で繋ぎましょう.
スタックを使っていなくてもスタックポインタを初期化する
これはどうしようも無いかも…….コンパイル後に手で消しましょう.というか,C言語でスタックを使わないプログラムとか書いてはいけません.