www.mikrocontroller.net

Forum: Compiler & IDEs Optimierungs-Bug mit Registern?


Autor: Wladimir Nickel (Firma: electronick.de) (wnickel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
AVR.
Ich benutze gerne einzelne Bits als Status-Flags für alle möglichen 
Zustände im Programm (Ersatz für bool). Damit es schneller geht, bringe 
ich die Bits in Registern unter. Zum ersten mal beobachte ich einen 
Optimierungsfehler:
volatile register struct {
  unsigned nibble:4;
  unsigned bit4:1;
  unsigned bit5:1;
  unsigned bit6:1;
  unsigned bit7:1;
} status asm("r2");

int main(void) {
  while(status.bit4);
}
aus der while-Schleife macht der GCC folgendes:
11:       int main(void) {
+0000001C:   2D82        MOV       R24,R2         Copy register
+0000001D:   7180        ANDI      R24,0x10       Logical AND with immediate
+0000001E:   2388        TST       R24            Test for Zero or Minus
+0000001F:   F7F1        BRNE      PC-0x01        Branch if not equal
13:       }
d.h. er holt R2 nur einmal in den R24, aber danach überprüft er R24 
immer wieder auf Null, ohne Ihn vorher zu beschreiben.

Wenn ich die Flags nicht im Register ablege:
volatile struct {
  unsigned nibble:4;
  unsigned bit4:1;
  unsigned bit5:1;
  unsigned bit6:1;
  unsigned bit7:1;
} status;

int main(void) {
  while(status.bit4);
}
funktioniert alles wie es soll:
11:       int main(void) {
+00000024:   91800060    LDS       R24,0x0060     Load direct from data space
+00000026:   FD84        SBRC      R24,4          Skip if bit in register cleared
+00000027:   CFFC        RJMP      PC-0x0003      Relative jump
13:       }
Bei diesem kleinen Beispiel nicht sichtbar, aber mein volles Programm 
wird um 300 Byte dicker, wenn ich die zweite Variante benutze. Und 
wahrscheinlich auch langsamer.
Ist das ein Bug, der gemeldet werden soll, oder ein Feature, das ich 
nicht verstehe?

Wie kann ich das Programm sonst noch veranlassen solange zu warten oder 
etwas zu tun, bis eine ISR ein flag setzt?

Danke.

Beitrag #2108886 wurde vom Autor gelöscht.
Autor: Stefan Ernst (sternst)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"volatile" und "register" funktioniert nicht zusammen. Das ist schon 
bekannt. Eigentlich sollte der Compiler auch eine entsprechende Warnung 
ausgeben.

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nun ja, erstens ist das Attribut "register" aus der C-Steinzeit, und 
zweitens ist die Semantic eines "volatilen Registers" per se irgendwie 
widersprüchlich.
Weil das so ist, wirft der gcc dazu auch eine warning:

>warning: optimization may eliminate reads and/or writes to register variables

Die gcc-Doku sagt dazu folgendes:
>The volatile modifier does not inhibit all optimizations that may eliminate 
>reads and/or writes to register variables.

Lange Rede, kurzer Sinn: Laß es sein. Register gehören dem Compiler, und 
sonst niemandem.

Oliver

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Oliver schrieb:
> Lange Rede, kurzer Sinn: Laß es sein. Register gehören dem Compiler, und
> sonst niemandem.

Dem kann ich nur zustimmen.

Die Situation ist ja auch deutlich entspannter, als zu Zeiten des 
ATtiny12.
Jetzt haben ja schon die 8-Pinner 8kB Flash/256Byte RAM, da muß man 
nicht mehr so geizig sein.
Oftmals nehme ich für ein Flag sogar ein ganzes Byte, spart etwas Code 
und Zeit.


Peter

Autor: Kai S. (zigzeg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Man koennte ein GCC asm statement in der while Schleife benutzen um dem 
Optimizer klar zu machen, das sich der Wert von R2 vielleicht geaendert 
hat. Der eigentliche assembler Block waere leer, aber man definiert R2 
als output parameter. Die GCC Hilfe (oder Google) sollten mit den 
Details helfen.

Kann nicht garantieren dass es funktioniert, ist halt so eine Idee.

Frage: Wie verhinderst Du eigentlich, dass der GCC das R2 register von 
sich aus benutzt ? Habe wohl irgendwo mal so eine Option gesehen, um ein 
globales Register zu reservieren. Erinnere mich aber nicht an Details.

Autor: Wladimir Nickel (Firma: electronick.de) (wnickel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Jetzt haben ja schon die 8-Pinner 8kB Flash/256Byte RAM, da muß man
> nicht mehr so geizig sein.

So einen 8kB-Teil habe ich und ich stehe schon mit dem Rücken zur Wand:
Size before:
tec-pwm.elf  :
section            size      addr
.text              7246         0

...

Size after:
tec-pwm.elf  :
section            size      addr
.text              7526         0
(nach dem löschen von register)

Kai S.:
> Frage: Wie verhinderst Du eigentlich, dass der GCC das R2 register von
> ich aus benutzt ?
http://www.nongnu.org/avr-libc/user-manual/FAQ.htm...
Irgendwie habe ich es damals so verstandanden, dass der Compiler nur 
R8-R32 und R0, R1 benutzt. Bis jetzt hat's funktioniert.

Danke an Alle, ich werde umdenken!

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die allererste Frage lautet doch: Was bringt dieses "Optimierung"? (bzw. 
was würde sie bringen, wenn das erzeugte Programm das täte, was es 
sollte?)

Ein MOV benötigt zwar einen (in Worten: Einen) Zyklus weniger, als ein 
LD, aber wenn es schon darauf ankommt, dann gute Nacht. Da wäre dann 
doch der Einsatz von handoptimiertem Assembler angeraten.

Oliver

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W. Nickel schrieb:

> .text              7526         0
> (nach dem löschen von register)

Klar.  Nicht, weil du "register" gelöscht hast, sondern weil die
"volatile"s nun endlich auch wirklich berücksichtigt werden.  Das sind
immer Pessimierungen.

Aber: ein ganzes Byte als Flag zu benutzen, kann dir codemäßig (und
nur daran klemmt es ja im Moment bei dir) billiger kommen als einzelne
Bits zu benutzen.  Letzteres ist nur dann interessant, wenn du mit dem
SRAM am Ende bist.

> Irgendwie habe ich es damals so verstandanden, dass der Compiler nur
> R8-R32 und R0, R1 benutzt.

Keineswegs, der benutzt auch die anderen, wenn es gebraucht wird.
Allerdings kannst du von R2 beginnend bis wenigstens ca. R7 dir
"private" Registervariablen reservieren (und sei es nur, damit du auf
diese anschließend in inline asm-Anweisungen zugreifen kannst).  Du
musst das allerdings in allen Übersetzungseinheiten gleichermaßen so
deklarieren.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
W. Nickel schrieb:
> So einen 8kB-Teil habe ich und ich stehe schon mit dem Rücken zur Wand:

Da ist bestimmt noch reichlich Optimierungspotential.
Wenn Du Lust hast, kannst Du ja mal den Code posten oder mir schicken.


Peter

Autor: Wladimir Nickel (Firma: electronick.de) (wnickel)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Peter Dannegger schrieb:
> Wenn Du Lust hast, kannst Du ja mal den Code posten oder mir schicken.

Danke für das Angebot, ich werde es erstmal selbst versuchen, zumal es 
ein Closed-Source-Projekt ist und ich damit Geld verdiene.

OffTopic. Darf ich mal eine private Frage stellen? Bist du Rentner?
Du scheinst viel Erfahrung und trotzdem viel Zeit zu haben ;-)

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.