2010年6月20日日曜日

avr-gcc4の吐き出すコードって、、

avr-gcc ver.3 (3.4.6) と ver.4 (4.4.3) の吐くコードがどのくらい違うのか調べてみたくなって、簡単なプログラムを書いて実際にコンパイルしてみた。 プログラム自体はたわいもないもので、attiny2313のPORTBに繋がっているLED8個を1つおきに交互に点滅させるというもの。 で、実際のプログラムはこんな感じ。

1 /* led.c, test program for LED on and off */
2
3 #include <avr/io.h>
4

5 int main(void)
6 {
7 unsigned int i;
8
9 DDRB = 0xff;
10 DDRD = 0x00;
11 PORTD = 0xff;
12
13 for(;;){
14 PORTB = 0x00;
15 PORTB = 0xaa;
16 for( i=0; i&lt;30000; i++){
17 asm volatile ("nop");
18 }
19
20 unsigned int j=30000;
21 PORTB = 0x00;
22 PORTB = 0x55;
23 do{
24 asm volatile ("nop");
25 }while(j--);
26 }
27 }


最初は for() と do-while でどのくらい吐き出すコードが違うのか調べたかったのだが、こちらは期待どおりというか、大した違いは無かった。片方は順番に変数がインクリメントされていくし、片方はディクリメントされていく。 ところが、面白かったのは、何気に使っている PORTB = 0x55; がどんな風に変換されているのか調べてみたら、使っている avr-gcc のバージョンによって吐かれるコードが結構違うことに気がついた。 使ったavr-gccのバージョンは上に書いた通り。 実際に吐かれたコードは、

ver 3.4.6 は、

PORTB = 0x55;
a8: 85 e5 ldi r24, 0x55 ; 85
aa: 80 93 38 00 sts 0x0038, r24

レジスタ24に0xaaをロードしてSRAMの0x0038番地にr24を出力。AVRはmemory maped IOなので PORTBもメモリマップ上にいる。

ver 4.4.3 だと、これが↓こうなる。

PORTB = 0x55;
c2: 88 e3 ldi r24, 0x38 ; 56
c4: 90 e0 ldi r25, 0x00 ; 0
c6: 25 e5 ldi r18, 0x55 ; 85
c8: fc 01 movw r30, r24
ca: 20 83 st Z, r18


ver.3 では 6バイトで書けたものが ver.4では 10バイトも必要になっている。で、最終結果にもそれがちゃんと(?)反映されていて、それぞれ

ver.3.4.6
avr-size led.elf
text data bss dec hex filename
198 0 0 198 c6 led.elf


ver.4.4.3
avr-size led.elf
text data bss dec hex filename
238 0 0 238 ee led.elf


ちなみに、アセンブラで書くならきっとこう書くはず。

ldi r18, 0x55
out PORTB, r18

4バイトか、、、 何かのコンパイルオプションでこの状況は解決されるのだろうか?

1 件のコメント:

kitax さんのコメント...

お久しぶりです。
gccの"-O"オプションでなんとかなりませんかね…。
確か、"-Os"でコードサイズ重視のオプティマイズを
してくれたハズ。WeW

++ Myself ++

普通(?)のサラリーマン -- 生活のすきま時間にキーボードとはんだごてを持ち替えてプログラミングと電子工作してます