Forum: Compiler & IDEs Optimierungs-Bug mit Registern?


von Wladimir N. (Firma: electronick.de) (wnickel)


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:
1
volatile register struct {
2
  unsigned nibble:4;
3
  unsigned bit4:1;
4
  unsigned bit5:1;
5
  unsigned bit6:1;
6
  unsigned bit7:1;
7
} status asm("r2");
8
9
int main(void) {
10
  while(status.bit4);
11
}
aus der while-Schleife macht der GCC folgendes:
1
11:       int main(void) {
2
+0000001C:   2D82        MOV       R24,R2         Copy register
3
+0000001D:   7180        ANDI      R24,0x10       Logical AND with immediate
4
+0000001E:   2388        TST       R24            Test for Zero or Minus
5
+0000001F:   F7F1        BRNE      PC-0x01        Branch if not equal
6
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:
1
volatile struct {
2
  unsigned nibble:4;
3
  unsigned bit4:1;
4
  unsigned bit5:1;
5
  unsigned bit6:1;
6
  unsigned bit7:1;
7
} status;
8
9
int main(void) {
10
  while(status.bit4);
11
}
funktioniert alles wie es soll:
1
11:       int main(void) {
2
+00000024:   91800060    LDS       R24,0x0060     Load direct from data space
3
+00000026:   FD84        SBRC      R24,4          Skip if bit in register cleared
4
+00000027:   CFFC        RJMP      PC-0x0003      Relative jump
5
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.

von Stefan E. (sternst)


Lesenswert?

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

von Oliver (Gast)


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

von Peter D. (peda)


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

von Kai S. (zigzeg)


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.

von Wladimir N. (Firma: electronick.de) (wnickel)


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:
1
Size before:
2
tec-pwm.elf  :
3
section            size      addr
4
.text              7246         0
5
6
...
7
8
Size after:
9
tec-pwm.elf  :
10
section            size      addr
11
.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.html#faq_reg_usage
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!

von Oliver (Gast)


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

von Jörg W. (dl8dtl) (Moderator) Benutzerseite


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.

von Peter D. (peda)


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

von Wladimir N. (Firma: electronick.de) (wnickel)


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 ;-)

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.