Forum: Compiler & IDEs avr-gcc verdoppelt code von Funktionsaufruf


von Andreas K. (andreasbw)


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"

von Klaus W. (mfgkw)


Lesenswert?

Es gibt eine Option -fwhole-program oder so ähnlich; damit vermute
ich ist der Effekt weg.

von Ansgar K. (paulderbademeister)


Lesenswert?

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

von Andreas K. (andreasbw)


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

von Rolf M. (rmagnus)


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.

von Ansgar K. (paulderbademeister)


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.

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.