Forum: Compiler & IDEs AVR GCC: Funktion wird weg optimiert... warum?


von digifloh (Gast)


Lesenswert?

Hi @ all,

ich habe ein kleines Problem wo mir ein erfahrener AVR C Programmierer 
bestimmt weiter helfen kann.

Ich rufe folgende Funktion...

void gen_hl() {
  PORTD = 127;
}

...mit...

gen_hl();

...auf.


Solange man den Optimierungs-Schalter auf -O0 (Ohh null) läst geht das 
auch alles. Stellt man um auf -Os was ja empfohlen wird dann ist der 
Optimierer aber fleißig... zu fleißig, er ruft die Funktion erst 
garnicht mehr auf... warum?


Gruß Frank

von Thomas (Gast)


Lesenswert?

Moin!

Es kann sein, dass du in der Klammer auch ein void setzen musst, sonst 
erkennt er es nicht als Funktion
1
void gen_hl(void) {
2
  PORTD = 127;
3
}


MfG

von Frank (Gast)


Lesenswert?

PORTD als volatile deklariert?

von Joerg X. (Gast)


Lesenswert?

Hast du nachgesehen, ob die Funktion ge"inlined" wird?, d.h. der 
Compiler setzt die Anweisung in der Funktion direkt ins Programm ein, 
anstatt die Funktion aufzurufen.

von digifloh (Gast)


Lesenswert?

Danke für die schnellen Antworten,

also (void) bringt nichts, das "komische ist, es läst sich noch nicht 
einmal ein Breakpoint setzen. Deutet wohl darauf hin das er es völlig 
ignoriert.

>> Hast du nachgesehen, ob die Funktion ge"inlined" wird?, d.h. der
>> Compiler setzt die Anweisung in der Funktion direkt ins Programm ein,
>> anstatt die Funktion aufzurufen

Ähm ok, was bedeutet das?
Wo würde man das sehen, was ist zu tun?

Gruß Frank

von Joerg X. (Gast)


Lesenswert?

> Ähm ok, was bedeutet das?
wenn die Anweisung ausgeführt wird, die in der Funktion steht, ist es 
doch egal.

> Wo würde man das sehen, was ist zu tun?
Sieht man im list-file (da stehen die Assemblerbefehle drin, aus denen 
das Prog im Endeffekt besteht

von digifloh (Gast)


Lesenswert?

Jo ok,

also da sieht es tatsache nicht so aus als ob es angesprungen wird.
Ich verstehe auch ASM, wollte aber nun ein Programm in C schreiben.

Geht das nicht in C das man eben wiederkehrende Sachen in eine Funktion 
legt?

Hmm hat noch jemand einen Tip warum es wohl wegoptimiert wird?

Wie würdet ihr eine Funktion beschreiben?

Das GCC Tour in dem Forum habe ich gesehen, das mache ich eigendlich so.

Verwende AVR Studio und WinAVR.


Gruß Frank'l

von Simon K. (simon) Benutzerseite


Lesenswert?

PORTD als volatile deklarieren? Wie geht denn das? ;)
Und was "void" in den Klammern bringen soll, ist mir auch schleierhaft. 
Warum sollte er den Ausdruck nicht als Funktion erkennen?

Woher nimmst du die Information, dass die Funktion nicht aufgerufen 
wird?

PS: Schau doch mal in dem Listfile (*.lst) nach, ob die Funktion 
aufgerufen/inlined wird.

von Joerg X. (Gast)


Lesenswert?

>> Hmm hat noch jemand einen Tip warum es wohl wegoptimiert wird?
weil der AUfruf (Rcall + push(evtl.) + ... pop + ret) länger 
dauert("teurer ist") als die eigentlich Funktion (ldi + out), wenn du 
eine längere Funktion schreibst oder die Funktion in eine andere 
"compilation-Unit" (.c-Datei) auslagerst, wird die nicht ge-"inlined".

von antworter (Gast)


Lesenswert?

Da PORTD garantiert als "volatile" deklariert ist, wird es gcc mit 
Sicherheit nicht wegoptimieren.

Wenn es Dir im ASM-Quelltext nicht über den Weg läuft, hast Du es 
bestimmt übersehen...

Probiere doch einfach mal, so ein minimal-Programm zu flashen, um Dir 
dann den PORT über ein Oszi anzuschauen.

Wenn es dann nicht geht, hat Dein uC vielleicht gar keinen PORTD (kommt 
gerne mal vor, daß soetwas übersehen wird)...

von *.* (Gast)


Lesenswert?

Inline bedeutet, dass anstatt "call gen_hl" der Inhalt von gen_hl() 
direkt an dieser Stelle ausgeführt wird. Macht bei einer so kleinen 
Funktion Sinn.

von digifloh (Gast)


Lesenswert?

Hallo nun ich hab mal den Code auf ein Mininmum reduziert, wie gesagt 
die -O Option ist auf -Os um den "schnellsten" Code zu erzeugen.

gen_off(); Wird nicht angesprungen... :-(

µC ist ein ATmega16 auf'n STK500 mit AVR Studio und WinAVR.


1
#include <stdlib.h> 
2
#include <avr/io.h>
3
#include <avr/interrupt.h>
4
5
volatile struct {
6
   unsigned bGen:1;
7
   unsigned bActLevel:1;
8
} fA1;
9
10
11
12
ISR(TIMER0_OVF_vect)
13
{
14
  if bit_is_set (PORTB,PIN0) { PORTB &= ~(1 << PIN0);}
15
              else { PORTB |=  (1 << PIN0);}
16
}
17
18
19
20
void gen_off(void) {
21
  PORTD = 127;
22
  fA1.bGen = 0;
23
}
24
25
26
27
int main (void) {
28
//--- PORT B ---
29
  DDRB  = 0xFF;            // PortD Datenrichtung setzen
30
  PINB  = 0;              // Pullups off
31
  PORTB = 0xFF;
32
33
//--- PORT D ---
34
  DDRD  = 0xFF;            // PortD Datenrichtung setzen
35
  PIND  = 0;              // Pullups off
36
  PORTD = 0xFF;
37
38
//--- Timer 0 ----------------------------------------------------------------
39
  TIMSK |= (1 << TOIE0);         // Interupt für Timer0 einschalten
40
  TCCR0 |= (3<<CS00);          // Vorteiler für T/C0 (3=CLOCK/64)
41
42
  gen_off();
43
44
  sei();
45
46
  while(1) {
47
  }
48
  return 0;
49
}

von Mark .. (mork)


Lesenswert?

Hallo digifloh,

zeig doch mal die .lst-Datei. Bestimmt ist die Funktion in diesem Fall 
geinlined worden, weil es dann einfach schneller geht. Solange die 
Wirkung aber diesselbe ist, sollte es eigentlich egal sein, ob die 
Funktion angesprungen wird oder nicht. Übrigens: -0s erzeugt nicht den 
schnellsten sondern den kleinsten Code. -03 erzeugt den schnellsten 
Code, in den meisten Fällen aber auch den größten.

MfG Mark

von Joerg X. (Gast)


Lesenswert?

Meinst du nicht, dass das ein bischen an den Haaren herbeigezogen ist, 
das Programm, das du gepostet hast tut (im Simulator) genau was es soll, 
PORTD wird vorher schon gesetzt, und die struct wird extra gesetzt.
 Demnach meint der gcc dass sich der Aufruf nicht rechnet (da hat der 
sicher recht).
 Du hast eine bessere chance eine Funktion zu beobachten wenn diese 
Parameter übernimmt oder werte zurückgibt. (und es gibt ein no_inline_ 
oder so änhlich -attribute und enstprechende GCC-Parameter, um die zu 
nutzen müsstest du allerdings das GCC-Manual lesen ...

hth. Jörg

von Tishima (Gast)


Lesenswert?

Hallo!

Ich weis zwar nicht was fuer ein Prozessor es ist, aber das kommt mit 
spanisch vor......


PINB  = 0;              // Pullups off

Ich denke die Zeile tut nicht das was als Kommentar da steht....


gruß,
Bjoern

von let (Gast)


Lesenswert?

Ich habe das letzte Programm mal durch den gcc gejagt.
'gen_off()' wird ge-inlined, die Funktion selbst ist
aber da. Sie wird halt nur nicht aufgerufen.
Die Funktion muß der Compiler auch erzeugen weil er nicht
wissen kann ob sie nicht von einem anderen Modul aus
aufgerufen wird.

Mit 'static' deklariert nimmt er sie aber raus.

Da habe ich gerade etwas dazugelernt: Ich dachte bisher immer
das der gcc nur mit -O3 inlining benutzt - abgesehen von statischen
Funktionen die nur einmal verwendet werden. Mit -O{0,1,2} wird die
Funktion aufgerufen.

 - Michael

von digifloh (Gast)


Angehängte Dateien:

Lesenswert?

@Jorg X.

Sicher ist es ein Programm was nur als Beispiel dient aber nicht 
unnöglich ist.
Beim START möchte ich einmal die Funktion aufrufen, das ist alles, ich 
gehe mal davon aus das es total egal ist was man da reinschreibt in der 
Funktion. Ob nun 150 ein A über den UART ausgegeben wird oder einfach 
nur der Wert 127 am PortD.

Kann es an meiner Timer Ini liegen?


Die lss Datei hab ich mal angehangen...


MfG Frank'l

von Joerg X. (Gast)


Lesenswert?

Es ist nicht egal, was in der Funktion drinsteht, solange der Compiler 
das weiß! -> wenn du die Funktion in eine andere .c-Datei schreibst, 
wird die auch aufgerufen, weil der Compiler nicht inlinen kann, und 
glaub mir, wenn inlinen keine Vorteile bringt wird der compiler es auch 
ganz lassen.

Können wir diese "Diskussion" fortsetzen, falls der GCC so inline't, 
dass das Programm nicht mehr funktioniert?

von digifloh (Gast)


Lesenswert?

Hallo,

@Joerg X.
Ja war vlt. etwas übertrieben, ich wollte nur sagen das es für das 
Verständniss Funktionen halt egal wäre was im eigendlichen in ihr steht.

Vielleicht wäre eine For Schleife besser... ;)

Ok Knackpunkt ist das inline, das wußte ich nicht.
Ich habe nun mal das prg Step für Step im Deassembler durchgeklickert... 
es macht inline wie du richtig angenommen hast...

Also muß mein Fehler woanders liegen, ich hab was gelernt und sogar 
verstanden was :-D

Das nächste mal wenn sich ein Punkt nicht anspringen läst schau ich hier 
als erstes nach.

Dank euch... schönen Sonntag...

von Oliver (Gast)


Lesenswert?

>Ok Knackpunkt ist das inline, das wußte ich nicht.

Der Knackpunkt ist nicht das inline, sondern, daß der gcc, genauso, wie 
andere Compiler auch, bei eingschalteter Optimierung Code erzeugt, der 
nicht mehr 1:1   rückwärts dem C-Quelltext zugeordnet werden kann. Das 
macht der nicht nur durch inlining, da gibt es noch viele andere 
"Schweinereien" :-)

Fazit:
Wenn du deinen Sourcecode Zeile für Zeile durchsteppen möchtest, geht 
das nur mit -O0. Andere Compiler verbieten von vorherein, Debuginfos für 
optimierte Programme zu erzeugen, der gcc ist da etwas großzügiger.

Oliver

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.