簡體   English   中英

avr-gcc在設置寄存器時生成匯編

[英]avr-gcc generated assembly when setting a register

我正在查看從以下C代碼生成的asm。

uint8_t anode = lednum / 4;
PORTB = (1 << anode);

我使用O2優化獲得以下內容:

00000040 <setout>:
  40:   86 95           lsr r24
  42:   86 95           lsr r24
  44:   21 e0           ldi r18, 0x01   ; 1
  46:   30 e0           ldi r19, 0x00   ; 0
  48:   08 2e           mov r0, r24
  4a:   01 c0           rjmp    .+2     ; 0x4e
  4c:   22 0f           add r18, r18
  4e:   0a 94           dec r0
  50:   ea f7           brpl    .-6     ; 0x4c
  52:   28 bb           out 0x18, r18   ; 24
  54:   08 95           ret

我得到的是lsr只是換了兩個(除以4),但為什么以下所有工作都在兩個寄存器中完成? 是因為1被解釋為int,16位或其他東西。 我想象只需要一個寄存器,例如r18。

[edit1]添加完整代碼

[edit2]根據http://gcc.gnu.org/wiki/avr-gcc#Register_Layout r18和r19可以在任何功能(不包括ISR)內使用而不進行恢復。 兩者都不在功能之外使用。

[edit3]完全最小的例子。

#include <avr/io.h>
#include <stdint.h>

void
setout(uint8_t lednum)
{
        uint8_t anode = lednum / 4;
        PORTB = (1 << anode);
}

void
main(void)
{
        while(1)
        {
            for (int i = 0; i < 10; ++i)
                setout(i);
        }
}

給我:

bin/scanner.elf:     file format elf32-avr


Disassembly of section .text:

00000000 <__vectors>:
   0:   0e c0           rjmp    .+28        ; 0x1e <__ctors_end>
   2:   15 c0           rjmp    .+42        ; 0x2e <__bad_interrupt>
   4:   14 c0           rjmp    .+40        ; 0x2e <__bad_interrupt>
   6:   13 c0           rjmp    .+38        ; 0x2e <__bad_interrupt>
   8:   12 c0           rjmp    .+36        ; 0x2e <__bad_interrupt>
   a:   11 c0           rjmp    .+34        ; 0x2e <__bad_interrupt>
   c:   10 c0           rjmp    .+32        ; 0x2e <__bad_interrupt>
   e:   0f c0           rjmp    .+30        ; 0x2e <__bad_interrupt>
  10:   0e c0           rjmp    .+28        ; 0x2e <__bad_interrupt>
  12:   0d c0           rjmp    .+26        ; 0x2e <__bad_interrupt>
  14:   0c c0           rjmp    .+24        ; 0x2e <__bad_interrupt>
  16:   0b c0           rjmp    .+22        ; 0x2e <__bad_interrupt>
  18:   0a c0           rjmp    .+20        ; 0x2e <__bad_interrupt>
  1a:   09 c0           rjmp    .+18        ; 0x2e <__bad_interrupt>
  1c:   08 c0           rjmp    .+16        ; 0x2e <__bad_interrupt>

0000001e <__ctors_end>:
  1e:   11 24           eor r1, r1
  20:   1f be           out 0x3f, r1    ; 63
  22:   cf e5           ldi r28, 0x5F   ; 95
  24:   d1 e0           ldi r29, 0x01   ; 1
  26:   de bf           out 0x3e, r29   ; 62
  28:   cd bf           out 0x3d, r28   ; 61
  2a:   0d d0           rcall   .+26        ; 0x46 <main>
  2c:   1e c0           rjmp    .+60        ; 0x6a <_exit>

0000002e <__bad_interrupt>:
  2e:   e8 cf           rjmp    .-48        ; 0x0 <__vectors>

00000030 <setout>:
  30:   86 95           lsr r24
  32:   86 95           lsr r24
  34:   21 e0           ldi r18, 0x01   ; 1
  36:   30 e0           ldi r19, 0x00   ; 0
  38:   08 2e           mov r0, r24
  3a:   01 c0           rjmp    .+2         ; 0x3e <__SP_H__>
  3c:   22 0f           add r18, r18
  3e:   0a 94           dec r0
  40:   ea f7           brpl    .-6         ; 0x3c <setout+0xc>
  42:   28 bb           out 0x18, r18   ; 24
  44:   08 95           ret

00000046 <main>:
  46:   40 e0           ldi r20, 0x00   ; 0
  48:   21 e0           ldi r18, 0x01   ; 1
  4a:   30 e0           ldi r19, 0x00   ; 0
  4c:   84 2f           mov r24, r20
  4e:   86 95           lsr r24
  50:   86 95           lsr r24
  52:   b9 01           movw    r22, r18
  54:   02 c0           rjmp    .+4         ; 0x5a <main+0x14>
  56:   66 0f           add r22, r22
  58:   77 1f           adc r23, r23
  5a:   8a 95           dec r24
  5c:   e2 f7           brpl    .-8         ; 0x56 <main+0x10>
  5e:   68 bb           out 0x18, r22   ; 24
  60:   4f 5f           subi    r20, 0xFF   ; 255
  62:   4a 30           cpi r20, 0x0A   ; 10
  64:   98 f3           brcs    .-26        ; 0x4c <main+0x6>
  66:   40 e0           ldi r20, 0x00   ; 0
  68:   f1 cf           rjmp    .-30        ; 0x4c <main+0x6>

0000006a <_exit>:
  6a:   f8 94           cli

0000006c <__stop_program>:
  6c:   ff cf           rjmp    .-2         ; 0x6c <__stop_program>

它看起來像是內聯的,但它仍然使用兩個寄存器而不是一個。

gcc 4.9.0稍微差一點,燒掉兩個寄存器加上一條指令相比你正在使用的任何東西。

#define PORTB (*(volatile unsigned char *)(0x18+0x20))
void setout(unsigned char lednum)
{
        unsigned char  anode = lednum / 4;
        PORTB = (1 << anode);
}

avr-gcc -O2 -mmcu=avr2 -c fun.c -o fun.o
avr-objdump -D fun.o

00000000 <setout>:
   0:   28 2f           mov r18, r24
   2:   26 95           lsr r18
   4:   26 95           lsr r18
   6:   81 e0           ldi r24, 0x01   ; 1
   8:   90 e0           ldi r25, 0x00   ; 0
   a:   02 2e           mov r0, r18
   c:   00 c0           rjmp    .+0         ; 0xe <setout+0xe>
   e:   88 0f           add r24, r24
  10:   0a 94           dec r0
  12:   02 f4           brpl    .+0         ; 0x14 <setout+0x14>
  14:   88 bb           out 0x18, r24   ; 24
  16:   08 95           ret

我同意約阿希姆,我認為1正在被提升到更大的范圍。 有點像人們犯下的錯誤:

float a;
...
a = a + 1.0;

如果你這樣做

#define PORTB (*(volatile unsigned char *)(0x18+0x20))
void setout(unsigned char one, unsigned char lednum)
{
        unsigned char  anode = lednum / 4;
        PORTB = (one << anode);
}

我明白了

00000000 <setout>:
   0:   66 95           lsr r22
   2:   66 95           lsr r22
   4:   06 2e           mov r0, r22
   6:   00 c0           rjmp    .+0         ; 0x8 <setout+0x8>
   8:   88 0f           add r24, r24
   a:   0a 94           dec r0
   c:   02 f4           brpl    .+0         ; 0xe <setout+0xe>
   e:   88 bb           out 0x18, r24   ; 24
  10:   08 95           ret

我認為編譯器強制該常量為規則的16位值,但優化器發現它不需要移位16位。 16位常數的分配仍然存在。 所以我認為約阿希姆釘了它...發一個答案,所以我們可以投票給它......

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM