avr-gcc verdoppelt code von Funktionsaufruf

#2003985
Lesenswert?

Hallo,

Ich hab heute wieder angefangen etwas mit dem ATTINY2313 zu basteln. 
Weil ich wenig Erfahrung mit C auf Mikrocontrollern hab, schau ich mir 
immer etwas genauer an, was der Compiler aus meinem C-Code macht. Das 
hilft mir einfach bei der Fehlersuche. Manchmal vergleiche ich auch, 
welche Variante eines Ausdrucks dabei den kleineren Code erzeugt.

Dabei hab ich festgestellt, daß bestimmte Programmteile dopplet im Code 
vorkommen.

Ich versteh nur nicht warum !

Die folgende Variante erzeugt ein 124 Byte langes Programm
----
1
#include "avr/io.h"
2
#include "avr/portpins.h"
3

4
static void init_display() {
5
  DDRA|= _BV(PD1) | _BV(PD0);
6
  DDRA|= _BV(PD1);
7
  DDRA|= _BV(PD0);
8
  DDRB|= _BV(PD2) | _BV(PD3) | _BV(PD4);
9
  PORTB= _BV(PD2) | _BV(PD3) | _BV(PD4);
10
  DDRD|= _BV(PD0) | _BV(PD1) | _BV(PD2) | _BV(PD3) | _BV(PD4) | _BV(PD5);// + P6;
11
}
12

13
// void init() { init_display(); }
14

15
int main(void) {
16
  init_display();
17
  //init();
18
  while (-1)
19
    asm("nop");
20
}
----
Schachtle ich das Unterprogramm eine Ebene tiefer, so erzeugt der gcc 
ein 152 Byte langes Programm
----
1
#include "avr/io.h"
2
#include "avr/portpins.h"
3

4
static void init_display() {
5
  DDRA|= _BV(PD1) | _BV(PD0);
6
  DDRA|= _BV(PD1);
7
  DDRA|= _BV(PD0);
8
  DDRB|= _BV(PD2) | _BV(PD3) | _BV(PD4);
9
  PORTB= _BV(PD2) | _BV(PD3) | _BV(PD4);
10
  DDRD|= _BV(PD0) | _BV(PD1) | _BV(PD2) | _BV(PD3) | _BV(PD4) |
11
_BV(PD5);// + P6;
12
}
13

14
void init() { init_display(); }
15

16
int main(void) {
17
  //init_display();
18
  init();
19
  while (-1)
20
    asm("nop");
21
}
----
Dabei ist dann der Code für init_display() doppelt vorhanden

Was mache ich falsch ?
Andreas

avr-gcc -Wall -g2 -gstabs -Os -fpack-struct -fshort-enums -std=gnu99 
-funsigned-char -funsigned-bitfields -v -mmcu=attiny2313 
-DF_CPU=8000000UL -MMD -MP -MF"main.d" -MT"main.d" -c -o"main.o" 
"../main.c"
#2004286
Lesenswert?

Ansgar K. schrieb:
> 1. Fall: Unterfunktion ist static, darf geinlined und wegoptimiert
> werden
> 2. Fall: Unterfunktion ist nicht stativ, daher wird geinlined aber nicht
> wegoptimiert, da es unbekannte aufrufe geben könnte
>
> => zweite Unterfunktion auch static machen und nochmal testen

Volltreffer !!!
Schachtelungstiefe(St) 1/2

beide Funktionen nicht static:
(St) -O0, -O1, -O2, -O3, -Os
  1  200  144  124  124  124
  2  216 <148> 152  152  152

eine Funktion static:
(St) -O0, -O1, -O2, -O3, -Os
  1  200  144  124  124  124
  2  216 <148> 152  152  152

beide Funktionen static:
(St) -O0, -O1, -O2, -O3, -Os
  1  200  144  124  124  124
  2  216  144  124  124  124
----
Hab was gelernt: statische Funktionen lassen sich problemloser 
optimieren.

Trotzdem ist es komisch, daß die Optimierung -O1 in 2 Situationen besser 
abschneidet als -Os

Andreas
#2005622
Lesenswert?

Andreas Kielkopf schrieb:
> Hab was gelernt: statische Funktionen lassen sich problemloser
> optimieren.

Naja, wenn eine Funktion nicht statisch ist, muß der Compiler davon 
ausgehen, daß sie noch von wo anders aus aufgerufen werden könnte. Er 
führt sie dann innerhalb dieser Übersetzungseinheit inline aus, 
generiert aber zusätzlich eine nicht-inline-Version für den Aufruf von 
außen.
#2006799
Lesenswert?

So, hier nochmal ein kurzer Nachtrag, mein letzter Beitrag war auf nem 
Smartphone getippt und daher kurz gehalten. Rolf hat mir den Großteil 
schon abgenommen und nochmal erklärt was static in diesem Fall für einen 
Unterschied macht.

Das "schlechtere" Ergebnis der höheren Optimierungsstufen liegt daran, 
dass -O1 kein inlineing betreibt. Die höhere Optimierungsstufen nutzen 
dies und produzieren dadurch zwar minimal längeren Code, der aber 
schneller ist und keinen Platz auf dem Stack verbraucht. Erst das 
static, das die Löschung der nicht-inline-Version erlaubt, macht 
inlineing durch die Bank besser.

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren