Forum: Mikrocontroller und Digitale Elektronik erzeugter Code von ICCAVR ineffizient


von Fiffi (Gast)


Lesenswert?

Hallo,

ich teste gerade die Codequalität der Demoversion von Imagecraft C
v6.29.

Hier ein Resultat:

///////////////////////////////////
// PORTB bit constants
#define LED_GREEN     4
#define LED_YELLOW     5
#define LED_RED       6

#pragma interrupt_handler uart0_rx_isr:iv_UART_RX
void uart0_rx_isr(void)
{
 char data = UDR;

 switch(data)
 {
 case LED_GREEN_ON:
  PORTD &= ~BIT(LED_GREEN);
  break;
 case LED_GREEN_OFF:
  PORTD |= BIT(LED_GREEN);
  break;
 case LED_YELLOW_ON:
  PORTD &= ~BIT(LED_YELLOW);
  break;
 case LED_YELLOW_OFF:
  PORTD |= BIT(LED_YELLOW);
  break;
 case LED_RED_ON:
  PORTD &= ~BIT(LED_RED);
  break;
 case LED_RED_OFF:
  PORTD |= BIT(LED_RED);
  break;
 }

 if(data == LED_GREEN_ON)
  PORTD &= ~BIT(LED_GREEN);
}
///////////////////////////////////
   *00000043:uart0_rx_isr
   +00000043: 930A      ST      -Y,R16
   +00000044: 932A      ST      -Y,R18
   +00000045: 933A      ST      -Y,R19
   +00000046: 93EA      ST      -Y,R30
   +00000047: B70F      IN      R16,0x3F
   +00000048: 930A      ST      -Y,R16
   +00000049: B10C      IN      R16,0xC
   +0000004A: 2F20      MOV     R18,R16
   +0000004B: 2733      CLR     R19
   +0000004C: 3021      CPI     R18,0x01          ; 0x01 = 0b00000001 =
1
   +0000004D: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +0000004E: 073E      CPC     R19,R30
   +0000004F: F0A9      BREQ    +0x15             ; Destination:
0x000065
   +00000050: 3022      CPI     R18,0x02          ; 0x02 = 0b00000010 =
2
   +00000051: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +00000052: 073E      CPC     R19,R30
   +00000053: F099      BREQ    +0x13             ; Destination:
0x000067
   +00000054: 3023      CPI     R18,0x03          ; 0x03 = 0b00000011 =
3
   +00000055: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +00000056: 073E      CPC     R19,R30
   +00000057: F089      BREQ    +0x11             ; Destination:
0x000069
   +00000058: 3024      CPI     R18,0x04          ; 0x04 = 0b00000100 =
4
   +00000059: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +0000005A: 073E      CPC     R19,R30
   +0000005B: F079      BREQ    +0x0F             ; Destination:
0x00006B
   +0000005C: 3025      CPI     R18,0x05          ; 0x05 = 0b00000101 =
5
   +0000005D: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +0000005E: 073E      CPC     R19,R30
   +0000005F: F069      BREQ    +0x0D             ; Destination:
0x00006D
   +00000060: 3026      CPI     R18,0x06          ; 0x06 = 0b00000110 =
6
   +00000061: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +00000062: 073E      CPC     R19,R30
   +00000063: F059      BREQ    +0x0B             ; Destination:
0x00006F
   +00000064: C00B      RJMP    +0x000B           ; Destination:
0x000070
   +00000065: 9894      CBI     0x12,4
   +00000066: C009      RJMP    +0x0009           ; Destination:
0x000070
   +00000067: 9A94      SBI     0x12,4
   +00000068: C007      RJMP    +0x0007           ; Destination:
0x000070
   +00000069: 9895      CBI     0x12,5
   +0000006A: C005      RJMP    +0x0005           ; Destination:
0x000070
   +0000006B: 9A95      SBI     0x12,5
   +0000006C: C003      RJMP    +0x0003           ; Destination:
0x000070
   +0000006D: 9896      CBI     0x12,6
   +0000006E: C001      RJMP    +0x0001           ; Destination:
0x000070
   +0000006F: 9A96      SBI     0x12,6
   +00000070: 3001      CPI     R16,0x01          ; 0x01 = 0b00000001 =
1
   +00000071: F409      BRNE    +0x01             ; Destination:
0x000073
   +00000072: 9894      CBI     0x12,4
   +00000073: 9109      LD      R16,Y+
   +00000074: BF0F      OUT     0x3F,R16
   +00000075: 91E9      LD      R30,Y+
   +00000076: 9139      LD      R19,Y+
   +00000077: 9129      LD      R18,Y+
   +00000078: 9109      LD      R16,Y+
   +00000079: 9518      RETI
///////////////////////////////////
Das Setzen/Rücksetzen der Port-Bits hat er richtig übersetzt.
Aber die switch() Anweisung ?:
   +00000050: 3022      CPI     R18,0x02          ; 0x02 = 0b00000010 =
2
   +00000051: E0E0      LDI     R30,0x00          ; 0x00 = 0b00000000 =
0
   +00000052: 073E      CPC     R19,R30
   +00000053: F099      BREQ    +0x13             ; Destination:
0x000067
Die If Anweisung hat er auch richtig übersetzt, warum dann nicht bei
der switch() Anweisung ?:
   +00000070: 3001      CPI     R16,0x01          ; 0x01 = 0b00000001 =
1
   +00000071: F409      BRNE    +0x01             ; Destination:
0x000073
   +00000072: 9894      CBI     0x12,4


Habt ihr ähnliche Erfahrungen ?

von Peter D. (peda)


Lesenswert?

Ohne einen vollständigen Code kann das keiner sagen:

error: `LED_GREEN_ON' undeclared (first use in this function)
error: (Each undeclared identifier is reported only once
error: for each function it appears in.)
warning: implicit declaration of function `BIT'
error: `LED_GREEN_OFF' undeclared (first use in this function)
error: `LED_YELLOW_ON' undeclared (first use in this function)
error: `LED_YELLOW_OFF' undeclared (first use in this function)
error: `LED_RED_ON' undeclared (first use in this function)
error: `LED_RED_OFF' undeclared (first use in this function)


Peter

von Fiffi (Gast)


Lesenswert?

Hallo Peter,

entschuldige bitte, hier sind die defines:

#define LED_GREEN_ON   1
#define LED_GREEN_OFF  2
#define LED_YELLOW_ON  3
#define LED_YELLOW_OFF 4
#define LED_RED_ON     5
#define LED_RED_OFF    6

von Fiffi (Gast)


Lesenswert?

Hallo,

der von AVRGCC 20030913 erzeugte Code sieht auch nicht besser aus:

INTERRUPT(SIG_UART_RECV)
{
  76:  78 94         sei
  78:  1f 92         push  r1
  7a:  0f 92         push  r0
  7c:  0f b6         in  r0, 0x3f  ; 63
  7e:  0f 92         push  r0
  80:  11 24         eor  r1, r1
  82:  2f 93         push  r18
  84:  8f 93         push  r24
  86:  9f 93         push  r25
 char data = UDR;
  88:  2c b1         in  r18, 0x0c  ; 12

 switch(data)
  8a:  82 2f         mov  r24, r18
  8c:  99 27         eor  r25, r25
  8e:  83 30         cpi  r24, 0x03  ; 3
  90:  91 05         cpc  r25, r1
  92:  b1 f0         breq  .+44       ; 0xc0
  94:  84 30         cpi  r24, 0x04  ; 4
  96:  91 05         cpc  r25, r1
  98:  34 f4         brge  .+12       ; 0xa6
  9a:  81 30         cpi  r24, 0x01  ; 1
  9c:  91 05         cpc  r25, r1
  9e:  61 f0         breq  .+24       ; 0xb8
  a0:  02 97         sbiw  r24, 0x02  ; 2
  a2:  61 f0         breq  .+24       ; 0xbc
  a4:  15 c0         rjmp  .+42       ; 0xd0
  a6:  85 30         cpi  r24, 0x05  ; 5
  a8:  91 05         cpc  r25, r1
  aa:  79 f0         breq  .+30       ; 0xca
  ac:  85 30         cpi  r24, 0x05  ; 5
  ae:  91 05         cpc  r25, r1
  b0:  4c f0         brlt  .+18       ; 0xc4
  b2:  06 97         sbiw  r24, 0x06  ; 6
  b4:  61 f0         breq  .+24       ; 0xce
  b6:  0c c0         rjmp  .+24       ; 0xd0
 {
 case LED_GREEN_ON:
  PORTD &= ~_BV(LED_GREEN);
  b8:  94 98         cbi  0x12, 4  ; 18
  break;
  ba:  0a c0         rjmp  .+20       ; 0xd0
 case LED_GREEN_OFF:
  PORTD |= _BV(LED_GREEN);
  bc:  94 9a         sbi  0x12, 4  ; 18
  break;
  be:  08 c0         rjmp  .+16       ; 0xd0
 case LED_YELLOW_ON:
  PORTD &= ~_BV(LED_YELLOW);
  c0:  95 98         cbi  0x12, 5  ; 18
  break;
  c2:  06 c0         rjmp  .+12       ; 0xd0
 case LED_YELLOW_OFF:
  PORTD |= _BV(LED_YELLOW);
  c4:  95 9a         sbi  0x12, 5  ; 18
  PORTD |= 0x04;
  c6:  92 9a         sbi  0x12, 2  ; 18
  break;
  c8:  03 c0         rjmp  .+6        ; 0xd0
 case LED_RED_ON:
  PORTD &= ~_BV(LED_RED);
  ca:  96 98         cbi  0x12, 6  ; 18
  break;
  cc:  01 c0         rjmp  .+2        ; 0xd0
 case LED_RED_OFF:
  PORTD |= _BV(LED_RED);
  ce:  96 9a         sbi  0x12, 6  ; 18
  break;
 }

 if(data == LED_GREEN_ON)
  d0:  21 30         cpi  r18, 0x01  ; 1
  d2:  09 f4         brne  .+2        ; 0xd6
  PORTD &= ~_BV(LED_GREEN);
  d4:  94 98         cbi  0x12, 4  ; 18
}
  d6:  9f 91         pop  r25
  d8:  8f 91         pop  r24
  da:  2f 91         pop  r18
  dc:  0f 90         pop  r0
  de:  0f be         out  0x3f, r0  ; 63
  e0:  0f 90         pop  r0
  e2:  1f 90         pop  r1
  e4:  18 95         reti

von Joerg Wunsch (Gast)


Lesenswert?

Gemäß dem C-Standard berechnen viele Compiler die switch()-Ausdrücke
als Typ `int'.

if then else

könnte ggf. besseren Code erzeugen.

von Michael (Gast)


Lesenswert?

Ich habe Deine Quelle mit IAR übersetzt. Ich hoffe, es fehlt nichts.

    45          __interrupt  void uart0_rx_isr(void)
     46          {
   \   __nearfunc __interrupt void uart0_rx_isr();
   \                     uart0_rx_isr:
   \   00000000   932A                       ST      -Y,R18
   \   00000002   931A                       ST      -Y,R17
   \   00000004   930A                       ST      -Y,R16
   \   00000006   B72F                       IN      R18,0x3F
     47           char data = UDR;
   \   00000008   B10C                       IN      R16,0x0C
     48
     49           switch(data)
   \   0000000A   2F10                       MOV     R17,R16
   \   0000000C   951A                       DEC     R17
   \   0000000E   F059                       BREQ    ??uart0_rx_isr_0
   \   00000010   951A                       DEC     R17
   \   00000012   F059                       BREQ    ??uart0_rx_isr_1
   \   00000014   951A                       DEC     R17
   \   00000016   F059                       BREQ    ??uart0_rx_isr_2
   \   00000018   951A                       DEC     R17
   \   0000001A   F059                       BREQ    ??uart0_rx_isr_3
   \   0000001C   951A                       DEC     R17
   \   0000001E   F059                       BREQ    ??uart0_rx_isr_4
   \   00000020   951A                       DEC     R17
   \   00000022   F059                       BREQ    ??uart0_rx_isr_5
   \   00000024   C00B                       RJMP    ??uart0_rx_isr_6
     50           {
     51           case LED_GREEN_ON:
     52            PORTD &= ~BIT(LED_GREEN);
   \                     ??uart0_rx_isr_0:
   \   00000026   9894                       CBI     0x12,0x04
   \   00000028   C009                       RJMP    ??uart0_rx_isr_6
     53            break;
     54           case LED_GREEN_OFF:
     55            PORTD |= BIT(LED_GREEN);
   \                     ??uart0_rx_isr_1:
   \   0000002A   9A94                       SBI     0x12,0x04
   \   0000002C   C007                       RJMP    ??uart0_rx_isr_6
     56            break;
     57           case LED_YELLOW_ON:
     58            PORTD &= ~BIT(LED_YELLOW);
   \                     ??uart0_rx_isr_2:
   \   0000002E   9895                       CBI     0x12,0x05
   \   00000030   C005                       RJMP    ??uart0_rx_isr_6
     59            break;
     60           case LED_YELLOW_OFF:
     61            PORTD |= BIT(LED_YELLOW);
   \                     ??uart0_rx_isr_3:
   \   00000032   9A95                       SBI     0x12,0x05
   \   00000034   C003                       RJMP    ??uart0_rx_isr_6
     62            break;
     63           case LED_RED_ON:
     64            PORTD &= ~BIT(LED_RED);
   \                     ??uart0_rx_isr_4:
   \   00000036   9896                       CBI     0x12,0x06
   \   00000038   C001                       RJMP    ??uart0_rx_isr_6
     65            break;
     66           case LED_RED_OFF:
     67            PORTD |= BIT(LED_RED);
   \                     ??uart0_rx_isr_5:
   \   0000003A   9A96                       SBI     0x12,0x06
     68            break;
     69           }
     70
     71           if(data == LED_GREEN_ON)
   \                     ??uart0_rx_isr_6:
   \   0000003C   3001                       CPI     R16,1
   \   0000003E   F409                       BRNE    ??uart0_rx_isr_7
     72            PORTD &= ~BIT(LED_GREEN);
   \   00000040   9894                       CBI     0x12,0x04
     73          }
   \                     ??uart0_rx_isr_7:
   \   00000042   BF2F                       OUT     0x3F,R18
   \   00000044   9109                       LD      R16,Y+
   \   00000046   9119                       LD      R17,Y+
   \   00000048   9129                       LD      R18,Y+
   \   0000004A   9518                       RETI

von Fiffi (Gast)


Lesenswert?

Hallo Michael,

vielen Dank, daß du den Code mit IAR übersetzt hast.

Das Ergebnis ist beeindruckend !

von thkais (Gast)


Lesenswert?

Wenn die Compiler ineffizient sind, programmiert man halt gleich in
Assembler. Man kann eben nicht alles haben ;)

von Fiffi (Gast)


Angehängte Dateien:

Lesenswert?

Hallo,

ich habe nun eine ganze Datei unter den verschiedenen Compilern
compiliert.
Diese habe ich ein wenig optimiert (if() anstatt switch() ...).

Das Ergebnis (Codegröße):

WinAVR 20030913:               302 Byte
Codevision Demoversion 1.23.9: 348 Byte
Imagecraft Demoversion 6.29:   382 Byte

@Michael
Ich wäre dir dankbar, wenn du die Datei mal an IAR anpassen und
compilieren könnte.

von Michael (Gast)


Angehängte Dateien:

Lesenswert?

Hallo Fiffi,

anbei das 'Compilatius' tastatur.lst, ohne es gelinkt zu haben. Es
müßte auch nur der Stackpointer gesetzt werden, wenn ich nicht etwas
übersehen habe. Optimierung auf höchste Ausführungsgeschwindigkeit
'-s9'; 220 Byte sind angesagt. Wenn man schnelle Interrupts braucht,
ist es vorteilhafter, dort keine Calls zu machen, da sonst viele
Register gerettet werden müssen.

von Stefan (Gast)


Lesenswert?

Beim gcc ist die Initialisierung (Memory nullsetzen etc) bereits mit
drin, das fehlt beim IAR-Listing.
Ohne die Initialisierung komme ich bei gcc auf 240 Bytes.

Ohne die Funktionsaufrufe im IR wirds sowohl bei IAR als auch bei gcc
noch ein gutes Stück weniger.

Die switch-Anweisung hast Du Dir totoptimiert, jetzt werden jedesmal
alle 6 ifs getestet. Nimmst Du if ... else, dann sparst Du viel Zeit
zur Laufzeit.

Stefan

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.