Forum: Compiler & IDEs avr-gcc optimiert nicht?


von Walter (Gast)


Lesenswert?

ich habe meinen Computer neu aufgesetzt, vermutlich auch mit neuer 
avr-gcc Version und jetzt kommt da folgender lss-Schnipsel raus:
      e8:  87 e9         ldi  r24, 0x97  ; 151
      ea:  99 e3         ldi  r25, 0x39  ; 57
    unsigned int i;

    for(i=0;i<WLC;i++)
      asm volatile ("nop");
      ec:  00 00         nop
      ee:  01 97         sbiw  r24, 0x01  ; 1
      f0:  00 97         sbiw  r24, 0x00  ; 0
      f2:  e1 f7         brne  .-8        ; 0xec <warte+0x4>

das subtrahieren von 0 war früher nicht da und ich möchte es auch in 
Zukunft nicht da haben, was kann ich tun?

gcc Version ist:
Target: avr
Configured with: ../src/configure -v --enable-languages=c,c++ 
--prefix=/usr/lib --infodir=/usr/share/info --mandir=/usr/share/man 
--bindir=/usr/bin --libexecdir=/usr/lib --libdir=/usr/lib 
--enable-shared --with-system-zlib --enable-long-long --enable-nls 
--without-included-gettext --disable-libssp --build=i686-linux-gnu 
--host=i686-linux-gnu --target=avr
Thread model: single
gcc version 4.8.2 (GCC)

und der Compiler-Aufruf:
avr-gcc -c -mmcu=atmega88 -I. -gstabs -DF_CPU=7372800UL  -Os 
-funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall 
-Wstrict-prototypes -Wa,-adhlns=cnc.lst  -std=gnu99 -MD -MP -MF 
.dep/cnc.o.d cnc.c -o cnc.o

von g457 (Gast)


Lesenswert?

für

> warte

-schleifen gibts delay_[um]s() oder Assembler.

HTH

von Walter (Gast)


Lesenswert?

g457 schrieb:
> für
>
>> warte
>
> -schleifen gibts delay_[um]s() oder Assembler.
>
> HTH

is recht, aber kannst Du auch was zu meiner die Frage sagen?

von Dr. Sommer (Gast)


Lesenswert?

Walter schrieb:
> das subtrahieren von 0 war früher nicht da und ich möchte es auch in
> Zukunft nicht da haben, was kann ich tun?
Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit. Wie hats 
das denn früher gemacht? Wie würdest du denn eine 16bit-Operation 
effizienter hinbekommen??

von Bernd K. (prof7bit)


Lesenswert?

Dr. Sommer schrieb:
> Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit.

Warum? Und warum vom selben Registerpaar? sbiw ist doch bereits eine 16 
bit operation, oder?

: Bearbeitet durch User
von (prx) A. K. (prx)


Lesenswert?

Dr. Sommer schrieb:
> Es wird aber gar nicht 0 subtrahiert, sondern das Carry-Bit.

Nö. Da wird ein Registerpaar auf 0 getestet. Unnötigerweise.

: Bearbeitet durch User
von Ingo (Gast)


Lesenswert?

Was genau stört dich denn daran? Ich meine wenn man in C programmiert 
kümmert man sich nur im äußersten Fall um Assembler.

von Ahab (Gast)


Lesenswert?

Walter schrieb:
> das subtrahieren von 0 war früher nicht da und ich möchte es auch in
> Zukunft nicht da haben, was kann ich tun?

Optimierung Abschalten. 8-Bit-Schleifenvariable verwenden.


Grund: Der GCC hat deine Schleife umgedreht, statt
>> for(i=0;i<WLC;i++)
macht er
>> for(i=WLC;i;--i)

warum? 'i' kann er schön im Register-Paar r24,r25 behalten, der 
Schleifenrumpf interessiert sich nicht für den Wert von 'i', insofern 
ist nur die richtige Anzahl an Schleifendurchläufen wichtig, den Rest 
darf er ändern wie er lustig ist.

Und Startwert WLC setzen, Subtraktion und Vergleich auf 0 ist eben 
"schicker" als
auf 0 Initialisieren, Addieren, 16-Bit-Vergleich mit WLC durchführen.

von g457 (Gast)


Lesenswert?

> is recht, aber kannst Du auch was zu meiner die Frage sagen?

Klar, hier nochmals Deine Frage:

> [..] was kann ich tun?

Für

> warte

-schleifen gibts fertige Funktionen wie delay_[um]s(), die kannst Du 
ohne Sorgen direkt benutzen. Oder Du kannst in selber in Assembler 
hinschreiben was Du genau haben willst.

HTH und nix für ungut

von Walter (Gast)


Lesenswert?

Ingo schrieb:
> Was genau stört dich denn daran? Ich meine wenn man in C programmiert
> kümmert man sich nur im äußersten Fall um Assembler.

nun, mich stört, dass das nur ein Beispiel war, wo es leicht zu erkennen 
ist.
Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz 
und Zeit verschwenden. Ich habe nach der Neuinstallatuion eben vorher 
und nachher verglichen.
Ich würde ja nichts sagen, wenn der gcc es halt nicht besser kann, aber 
er konnte das schon Mal

von Falk B. (falk)


Lesenswert?

@ Walter (Gast)

>nun, mich stört, dass das nur ein Beispiel war, wo es leicht zu erkennen
>ist.
>Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz

Oh Gott, 2 Bytes!

>und Zeit verschwenden.

Einen Takt.

>Ich würde ja nichts sagen, wenn der gcc es halt nicht besser kann, aber
>er konnte das schon Mal

Wahrscheinlich sind die falschen Compilerschalter gesetzt. Ausserdem ist 
i ein INT, und der ist nunmal 16 Bit. Den kann der Compiler nur bedingt 
kleiner machen. Mach es so, dann ist deine Schleife maximal schnell.


1
#include <stdint.h>
2
#define nop() asm volatile("nop")
3
#define WLC 100
4
5
int main (void) {
6
    uint8_t i;
7
8
    for(i=WLC;i>0;i++)
9
      asm volatile ("nop");
10
}


1
  6c:  84 e6         ldi  r24, 0x64  ; 100
2
    uint8_t i;
3
4
    for(i=WLC;i>0;i++)
5
      asm volatile ("nop");
6
  6e:  00 00         nop
7
#define WLC 100
8
9
int main (void) {
10
    uint8_t i;
11
12
    for(i=WLC;i>0;i++)
13
  70:  8f 5f         subi  r24, 0xFF  ; 255
14
  72:  e9 f7         brne  .-6        ; 0x6e <main+0x2>
15
      asm volatile ("nop");
16
}
17
  74:  80 e0         ldi  r24, 0x00  ; 0
18
  76:  90 e0         ldi  r25, 0x00  ; 0
19
  78:  08 95         ret

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Oh Gott, 2 Bytes!
>
>>und Zeit verschwenden.
>
> Einen Takt.

oder 30% mehr Platz und 30% langsamer - so könnte man es auch sehen.

von Falk B. (falk)


Lesenswert?

Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt.

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt.

aber wenn man ihm glauben kann, dann würde ich auch der Grund 
interessieren warum es schon mal anders ging.

Das hat wohl nicht mit "Hochoptimierung" zu tun, sondern ist eventuell 
wirklich ein Bug.

von Rolf M. (rmagnus)


Lesenswert?

Ahab schrieb:
> Und Startwert WLC setzen, Subtraktion und Vergleich auf 0 ist eben
> "schicker" als auf 0 Initialisieren, Addieren, 16-Bit-Vergleich mit WLC
> durchführen.

Das ist es aber nur dann wirklich, wenn er nach der Subtraktion nicht 
noch eine unnötige zweite Subtraktion mit 0 einfügt. Die stellt nämlich 
genau den Vergleich dar, den man sich durch das Umdrehen der 
Zählrichtung eigentlich einsparen wollte.

Falk Brunner schrieb:
>>Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz
>
> Oh Gott, 2 Bytes!
>
>>und Zeit verschwenden.
>
> Einen Takt.

Ich finde die Frage, warum der Compiler auf einmal schlechter optimiert 
als eine frühere Version und warum er zusätzliche Instruktionen einfügt, 
durchaus gerechtfertigt.

> Wahrscheinlich sind die falschen Compilerschalter gesetzt.

Wleche sollten das denn sein?

> Ausserdem ist i ein INT, und der ist nunmal 16 Bit.

Ja, und? Bei 16 Bit muss man zwingend beim Zählen in jedem 
Schleifendurchlauf nochmal 0 vom Wert abziehen und bei 8 Bit nicht?

> Mach es so, dann ist deine Schleife maximal schnell.

WLC ist aber nicht 100, sondern offenbar 14743. Wie soll das in 8 Bit 
passen?

Falk Brunner schrieb:
> Wenn hochoptimale Ergebnisse will/braucht, MUSS Assembler nutzen. Punkt.

Das ist zwar richtig, aber trotzdem keine Begründung für eine schlechte 
Optimierung.

von Falk B. (falk)


Lesenswert?

@ Rolf Magnus (rmagnus)

>Ich finde die Frage, warum der Compiler auf einmal schlechter optimiert
>als eine frühere Version und warum er zusätzliche Instruktionen einfügt,
>durchaus gerechtfertigt.

Ja.

>> Wahrscheinlich sind die falschen Compilerschalter gesetzt.

>Wleche sollten das denn sein?

Kenn ich mich im Detail auch nicht aus.

>> Ausserdem ist i ein INT, und der ist nunmal 16 Bit.

>Ja, und? Bei 16 Bit muss man zwingend beim Zählen in jedem
>Schleifendurchlauf nochmal 0 vom Wert abziehen und bei 8 Bit nicht?

Sicher, wenn kein Optimierung eingeschaltet ist, denn es ist eine 16 Bit 
Subtraktion, welche auf einem 8 Bit Prozessor meistens zwei 
Subtraktionen (einmal Low Byte und eimal high Byte + Carry) benötigt.
Mit aktiver Optimierung macht der avr gcc ein subiw draus, wodurch eine 
16 Bit Subtraktion mit einem Befehl, wenn gleich auch 2 Takten erfolgen 
kann.

>> Mach es so, dann ist deine Schleife maximal schnell.

>WLC ist aber nicht 100, sondern offenbar 14743. Wie soll das in 8 Bit
>passen?

Womit man so oder so eine 16 Bit Subtraktion braucht.

von Peter II (Gast)


Lesenswert?

Falk Brunner schrieb:
> Womit man so oder so eine 16 Bit Subtraktion braucht.

das ist ja ok, nur die Frage warum er 2 16bit Subtraktion macht steht 
ja.

von Bernd K. (prof7bit)


Lesenswert?

Walter schrieb:
> Es tritt aber nicht nur da auf und ich möchte halt nicht unnötig Platz
> und Zeit verschwenden.

Du kannst (und sollst!) nichts anderes machen als Deinen Code 
(menschenlesbar!) hinschreiben und davon ausgehen dass der Compiler 
einigermaßen gut optimiert. Einigermaßen bedeutet er tut alles was in 
seiner Macht steht und das ist unterm Strich schon nicht schlecht. An 
einigen Stellen wird er sogar Optimierungen finden an die hättest selbst 
Du nicht gedacht, an anderen Stellen hättest Du vielleicht von Hand noch 
2 Takte rausgekitzelt oder ein paar Bytes gespart aber unterm Strich ist 
der gcc schon gar nicht mal so schlecht. Manchen sagen sogar er ist 
eigentlich ganz gut und auf jeden Fall ist er mindestens doppelt so gut 
wie die kastrierten 8 Bit Compiler von Microchip für PIC.

Das Wichtigste ist daß Du Deinen Code hinschreiben kannst ohne Dir 
allzuviele Gedanken darüber zu machen und darauf zählen kannst daß beim 
Compilieren kein haarsträubender Unsinn rauskommt. Wo Du die Grenze von 
"haarsträubend" hinlegst ist natürlich eine persönliche Entscheidung, 
aber ich würde sie nicht näher als vielleicht 20% vom theoretischen 
Optimum entfernt hinlegen und das schafft der gcc allemal.

von Peter II (Gast)


Lesenswert?

Bernd K. schrieb:
> Wo Du die Grenze von
> "haarsträubend" hinlegst ist natürlich eine persönliche Entscheidung,
> aber ich würde sie nicht näher als vielleicht 20% vom theoretischen
> Optimum entfernt hinlegen und das schafft der gcc allemal.

scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann 
liegt er 100% daneben.

Es geht darum, das er es schon mal besser gemacht hat!

von Bernd K. (prof7bit)


Lesenswert?

Peter II schrieb:
> scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann
> liegt er 100% daneben.

Ich dachte es geht um das gesamte Programm und das was unterm Strich 
an verpasster Einsparung übrig bleibt (so hab ich den zitierten Teil 
verstanden, darauf bezog ich mich).

Vorzeitige (Mikro-)Optimierungen sind die Wurzel allen Übels und 
verschwendete Lebenszeit. Von zehntausend Zeilen in Deinem Programm 
werden vielleicht nachher nur zwei Dutzend wirklich zeitkritisch sein 
und 90% der CPU-Zeit verbrauchen. Das findest Du leicht mit geeigneten 
Profiling-Techniken raus und dann kannst Du Dich auf diesen einen Teil 
konzentrieren (falls es sich überhaupt als nötig erweist [meistens 
nicht]).

Und in den 9976 übrigen Zeilen gibts bestenfalls noch leichte 
Ersparnisse an Flashverbrauch rauszuholen mit nem besseren Compiler 
(sofern sowas überhaupt existiert) aber wahrscheinlich nicht mehr als 
20%, also sch*** drauf, nimms wie es ist, es ist schon verdammt gut so 
wie es ist, sehr viel besser wirds nicht mehr werden und spar Dir die 
Zeit über diesen belanglosen Nebenkriegsschauplatz nachzugrübeln, es 
bringt nichts.

Wenns an dieser einen Stelle wirklich schon mal besser funktioniert hat 
und man das nachvollziehbar nachstellen kann und Dich das so sehr wurmt 
hilft vielleicht auch ein Bug-Report aber ich würde nicht versuchen die 
Luft anzuhalten bis es gefixt ist.

von Walter (Gast)


Lesenswert?

Peter II schrieb:
> scheinbar nicht. Wenn er statt eine Anweisung 2 Anweisungen macht, dann
> liegt er 100% daneben.
>
> Es geht darum, das er es schon mal besser gemacht hat!

genau so ist es.
Wie gesagt, ich beschwere mich nicht wenn ein open source tool nicht das 
macht was ich will, aber es ging schon Mal deutlich besser und ich würde 
gern wissen warum.
Vielleicht  mache ich ja auch einen Fehler, aber den Schalter -Os habe 
ich gesetzt wie immer und überhaupt ist der makefile auch der gleiche 
wie vorher.

von (prx) A. K. (prx)


Lesenswert?

Bernd K. schrieb:
> Vorzeitige (Mikro-)Optimierungen sind die Wurzel allen Übels und
> verschwendete Lebenszeit.

Hier ist offenbar nur jemandem die selbst gebaute Delay-Loop um die 
Ohren geflogen. Das frustet natürlich, liegt aber am falschen Ansatz, 
weniger am Compiler.

von Peter II (Gast)


Lesenswert?

avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.1_798) 4.6.2

liefert:

  bc:  8c ed         ldi  r24, 0xDC  ; 220
  be:  95 e0         ldi  r25, 0x05  ; 5
  c0:  00 00         nop
  c2:  01 97         sbiw  r24, 0x01  ; 1
  c4:  e9 f7         brne  .-6        ; 0xc0 <__vector_16+0x12>

1
#include <avr/io.h>
2
#include <avr/interrupt.h>
3
4
#define WLC 1500
5
6
/****************************************************************************/
7
ISR( USART0__RX_vect )
8
{
9
   int i;
10
   for(i=0;i<WLC;i++) {
11
      asm volatile ("nop");   
12
   }
13
}
14
15
/****************************************************************************/
16
int main(void)
17
{
18
   while(1);
19
}

von (prx) A. K. (prx)


Lesenswert?

Kann durchaus sein, dass in einer bestimmten Version des Compilers ein 
anderes suboptimales Ergebnis rauskommt. Und das später dann vielleicht 
wieder korrigiert ist. Das ist nicht schön, kann aber passieren.

von Peter II (Gast)


Lesenswert?

A. K. schrieb:
> Hier ist offenbar nur jemandem die selbst gebaute Delay-Loop um die
> Ohren geflogen. Das frustet natürlich, liegt aber am falschen Ansatz,
> weniger am Compiler.

es geht doch nicht im das delay. Man kann eine LED blinken lassen und 
das gleiche Problem entsteht.

Es geht darum, das der Compiler (scheinbar) schlechter geworden ist. 
Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen?`

von (prx) A. K. (prx)


Lesenswert?

Peter II schrieb:
> Es geht darum, das der Compiler (scheinbar) schlechter geworden ist.
> Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen?`

4.7.2 ist auch ok. 4.8.irgendwas gibts in debian-sid, müsste man mal 
probieren.

> es geht doch nicht im das delay. Man kann eine LED blinken lassen und
> das gleiche Problem entsteht.

Jo, aber der Code ist ja nicht falsch, nur suboptimal. Was bei einer 
Delay-Loop fatal sein kann.

: Bearbeitet durch User
von Walter (Gast)


Lesenswert?

Peter II schrieb:
> Kann es jemand anders mit einem neuer als den 4.6.2 mal nachstellen?

wäre nett, dann würde ich wenigstens wissen ob's an mir liegt

von Walter (Gast)


Lesenswert?

A. K. schrieb:
> 4.7.2 ist auch ok. 4.8.irgendwas gibts in debian-sid, müsste man mal
> probieren.

habe ich von Atmel direkt geladen

von Bernd K. (prof7bit)


Lesenswert?

Peter II schrieb:
> Es geht darum, das der Compiler (scheinbar) schlechter geworden ist.

Die aktuelle ofizielle gcc Toolchain von Atmel fixt aber auch einige 
Bugs die vorher drin waren. Zum Beispiel hat eine ältere Version (ich 
glaub es war die bei Ubuntu (12 oder 14) mitgelieferte) einfach mal 
globale Registervariablen wegoptimiert. Komplett wegoptimiert samt allen 
Codes der sie verwendet hat! Einfach weg!

Die aktuelle Atmel-Toolchain von deren Webseite macht das nicht mehr. 
Deshalb verwende ich jetzt nur noch die. Solche Showstopper (oder besser 
deren Abwesenheit) wären mir wichtiger als irgendeine winzige vergessene 
Optimierung.

von Dispol (Gast)


Lesenswert?

Ich habs das gleiche "Problem" mit 4.8.2

von Peter II (Gast)


Lesenswert?

Walter schrieb:
> wäre nett, dann würde ich wenigstens wissen ob's an mir liegt

kann es auch im

avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.5_1522) 4.8.1

nachstellen:

  96:  8c ed         ldi  r24, 0xDC  ; 220
  98:  95 e0         ldi  r25, 0x05  ; 5
  9a:  00 00         nop
  9c:  01 97         sbiw  r24, 0x01  ; 1
  9e:  00 97         sbiw  r24, 0x00  ; 0
  a0:  e1 f7         brne  .-8        ; 0x9a

von Walter (Gast)


Lesenswert?

Dispol schrieb:
> Ich habs das gleiche "Problem" mit 4.8.2

Peter II schrieb:
> kann es auch im
>
> avr-gcc (AVR_8_bit_GNU_Toolchain_3.4.5_1522) 4.8.1
>

Danke, dann muss ich wohl damit leben.
Schade dass 1,05 Schritte vorwärts, einer zurück wohl ein Naturgesetz 
ist ;-)

von Dispol (Gast)


Lesenswert?

>Schade dass 1,05 Schritte vorwärts, einer zurück wohl ein Naturgesetz
>ist ;-)
Ist GCC nicht OpenSource? Dann kann man ja selbst "mitschreiten".

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Walter schrieb:
> das subtrahieren von 0 war früher nicht da und ich möchte es auch in
> Zukunft nicht da haben, was kann ich tun?
>
> gcc version 4.8.2 (GCC)

Vermutlich PR60486, behoben in 4.8.3+, evtl. auch PR61055, behoben in 
4.8.3+ und 4.9.1+:

http://gcc.gnu.org/PR60486
http://gcc.gnu.org/PR61055

von Walter (Gast)


Lesenswert?

Danke Johann

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.