www.mikrocontroller.net

Forum: Compiler & IDEs Bug in WinAVR oder wieso macht der Compiler so einen Müll ?


Autor: Benedikt (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Ich wollte eigentlich nur das Programm durch Verwenden der uart Routinen
als Inline beschleunigen, aber mit Inline funktioniert garnichts mehr.
Also habe ich mir den erzeugten Code angeschaut (Optimierung aus
Codegröße) und diesen Mist gefunden (ohne inline):

- Der Compiler liest der Stackpointer ein, Manipuliert den Wert und
schreibt ihn am Ende wieder korrekt zurück, obwohl der Stackpointer nie
benötigt wird.
- Der Compiler schaltet die Interrupts für die gesamte Funktion aus.
- Der Compiler legt lokalen Variablen in den RAM obwohl die Register
reichen würden.

Kann mir jemand erklären, warum der Compiler so einen Mist macht ?

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

Bewertung
0 lesenswert
nicht lesenswert
> Kann mir jemand erklären, warum der Compiler
> so einen Mist macht ?

Er macht zumindest weniger ,,Mist'' als du beim Interpretieren
seines Codes.

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
hallo,
du hast da meiner meinung nach sehr stark vereinfacht.

der stackpointer wird manipuliert, das ist fakt. aber der reihe nach.

also zuerst wird der SP in r28 und r29 geladen, und dieses dann mit
'sbiw r28,1' um einen dekrementiert (ist eine word-operation,
betrifft also auch r29)

danach wird mit 'in _tmp_reg_,__SREG__' das statusregister gerettet
in ein temporäres register. wozu? um danach den alten zustand wieder
herstellen zu können, denn mit dem nachfolgendem 'cli' wird das
I-Flag des status-registers SREG gelöscht. die irq's ausgeschaltet.

dann wird der stack high geschrieben 'out _SP_H_,r29'.

so, jetzt wird das SREG wieder hergestellt: out _SREG_,__tmp_reg__
das bedeutet auch, das, wenn vorher dem 'cli' die irq's an waren,
sind sie auch wieder an, und umgekehrt auch! warum erst nachher das
low-byte des stack geschrieben wird, weiß ich nicht.

bye kosmo

Autor: Stefan Kleinwort (_sk_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Kann mir jemand sagen, warum der Compiler die IR sperrt?
Ich sehe im Quellcode nichts, was ihn sazu veranlassen könnte.
Oder fehlt vom Quellcode noch etwas wichtiges?

Danke, Stefan

Autor: kosmonaut pirx (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
um die atomarität sicherzustellen, vermute ich. d.h. zum geschriebenen
r29 muss das vorhergehende r28 passen.

nötig sind zwei cycles für das schreiben des 16bit-SP. wäre vll dumm,
nach dem schreiben des ersten bytes von nem irq unterbrochen zu werden,
der dann möglicherweise 'böse' ist und irgendwas verändert. dann würde
das andere byte geschrieben, aber passt nicht mehr zum veränderten
wert.

'out' ist atomar 1 cycle. also ist es vollkommen legal, das cli schon
vor dem zweiten 'out' wieder rückgängig zu machen.

oder, jörg?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mein Exemplar von WinAVR erzeugt völlig anderen Code, sowohl mit also
auch ohne Optimierung. Den vollständigen Stack-Frame kriege ich nur
ohne Optimierung, dann aber wird rr28 auch zu Adressierung lokaler
Daten benutzt. Welche Version, welche Compiler-Flags?

Der Stack-Pointer wird nach rr28 kopiert, wo er als Basis zur
Adressierung lokaler Daten dient. Allerdings macht er das bei mir nur
wenn auch nötig.

"Kann mir jemand sagen, warum der Compiler die IR sperrt?"

Überleg mal was passiert, wenn mitten in der Manipulation des
Stack-Pointers ein Interrupt eintrifft.

"Optimierung aus"

Dann erwarte bitte auch keinen optimalen Code.

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
"das cli schon vor dem zweiten 'out' wieder rückgängig zu machen."

Liegt an einer Eigenheit des AVR: Bei SEI ist dokumentiert, dass nach
dem Einschalten von Interrupts immer erst der nächste Befehl ausgeführt
wird (dieses Verhalten ist für den Sleep-Mode einigermassen wichtig).
Bei OUT SREG ist das auch so, nur nicht dokumentiert.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Anscheinend kommt der Compiler nicht mit dem selbst erstellen Array
zurecht, das ich in den externen RAM gelegt habe:
http://www.mikrocontroller.net/forum/read-2-417813.html#new

typedef unsigned char (*fram)[XSize];
const fram pixel = (fram)0x8000;

Jetzt habe ich die noinit section in den externen RAM verlagert und in
der noinit section das unsigned char [YSize][XSize] Array erstellt, und
der Code sieht normal aus. Jetzt kommt die Funktion komplett ohne
push/pop aus.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein, doch nicht. Ich hatte mich verschaut.
Auch mit einem normalen Array macht der Compiler diesen Mist.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nur wenn ich die uart_getchar() Funktion als inline deklariere, wird der
 Code normal (sogar ohne push und pops). Dafür funktioniert das Programm
aber nichtmehr...

#define FT245_Data      _SFR_MEM8((unsigned)256*16)
#define RXF      (PIND&32)

_inline_ static unsigned char uart_getchar(void)
{  while (RXF);
  return FT245_Data;
}

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es war ein Timingproblem mit dem FT245, jetzt geht die Software mit der
uart_getchar Funktion auch als inline.

Aber auch hier bläht der Compiler den Code unnötig auf:
Aus

while (PIND&32);
return FT245_Data;

macht er machnmal
.L44:
sbic 48-0x20,5
rjmp .L44
lds r24,4096

aber manchmal auch
.L48
in r24,48-0x20
clr r25
movw r18,r24
andi r18,lo8(32)
andi r19,hi8(32)
sbrc r24,5
rjmp .L48
lds r24,4096

Autor: Aufreger deluxe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Aber auch hier bläht der Compiler den Code unnötig auf

Es ist bekannt, dass WinAVR unnötig großen Code erzeugt.

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

Bewertung
0 lesenswert
nicht lesenswert
Es ist bekannt, dass WinAVR gar keinen Code erzeugt.

Es installiert nämlich nur die Tools.  WinAVR ist kein Compiler.

Es ist aber auch bekannt, dass Compiler manchmal Dinge machen,
die man als Mensch so nicht machen würde, dafür sind es Maschinen.
Zuweilen tun sie das sogar zum Positiven: dank ihrer stupiden
Vorgehensweise entdecken sie Optimierungen, für die wir als Mensch
ein Brett vorm Kopf haben.  Zuweilen coden sie natürlich auch
Dinge, von denen ein Mensch sofort offensichtlich sagt, dass man
dies oder jenes weglassen kann.

Es ist auch bekannt (nach dem Lesen dieses Threads), dass der Herr
Benedikt sichtlich Probleme hat, funktionierenden Code zu
verfassen und erst Recht welche, den generierten Code vernünftig
im ersten Anlauf zu interpretieren.  Ich bin mir bei obigem
Code-Schnipsel ziemlich sicher, dass der Compiler nicht erst
rr18/19 belegt, um dann trotzdem nur r24 auszuwerten.  Das lässt
sich aber nur im gesamten Kontext erkennen.  Außerdem dürfen sich
auch Compiler weiter entwickeln, und GCC 3.4.6 ist natürlich nicht
mehr der Stein der Weisen -- GCC 4.1.x generiert im Allgemeinen
für den AVR bereits deutlich kompakteren Code.

Autor: Karl Heinz (kbuchegg) (Moderator)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da möchte ich auch noch meinen Senf dazugeben:
Es ist auch bekannt, dass Compiler im Allgemeinen besseren
Assembler Code produzieren als ca. 95% aller Programmierer.
Mit anderen Worten: Um die meisten Compiler zu schlagen, muss
man schon ziemlich gut in Assembler sein. Jemand der nur ab
zu in Assembler programmiert hat gegen einen vernünftigen
Compiler so gut wie keine Chance.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Jörg

"... GCC 3.4.6 ist natürlich nicht mehr der Stein der Weisen -- GCC
4.1.x generiert im Allgemeinen für den AVR bereits deutlich kompakteren
Code."


Das neueste WINAVR installiert aber nur 3.4.6
Wie kann man denn auf 4.1.x updaten ?


Peter

Autor: Aufreger deluxe (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Es ist bekannt, dass WinAVR gar keinen Code erzeugt.
> Es installiert nämlich nur die Tools.  WinAVR ist kein
> Compiler.

WinAVR installiert auch keine Tools, dass mach der Installer.

Autor: Hans (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
ich liebe immer diese "bug reports"...

man beachte folgendes regelwerk:
1. der compiler hat immer recht (ausgenommen er kommt direkt aus dem
cvs.. dann hat er nur fast immer recht) vorallem wenn er aus der GCC
stammt
2. ein compiler der gut optimiert erzeigt immer code den man nicht
versteht
3. rtfm
4. rtfw
5. bugreports erst wenn die neuste version auch den bug hat (ich nehme
mal an dass es was neueres gibt wenn jörg schonmal meint 3.4.6
nichtmehr der stein der weisen sei...)
6. poste alle infos sonst bekommt man keine klaren bzw nützlichen
antworten

Autor: JojoS (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
'Das neueste WINAVR installiert aber nur 3.4.6
Wie kann man denn auf 4.1.x updaten ?'

das ist auf der Seite von P. Fleury beschrieben. Habe ich zufällig bei
unserer Bootloader Diskussion entdeckt, er hat seine letzte Version
bereits mit dem 4.1 übersetzt.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Hans

Was brauchst du noch an Infos ?

Ich habe den Code der kompletten Funktion einschließlich aller
Funktionen die darin aufgerufen werden gepostet.

Und falls der Compiler recht hat, dann kann mir bestimmt jemand
erklären warum der Compiler diesen (aus seiner Sicht) sinnvollen Weg
eingeht.


Gibt es eigentlich demnächst wieder mal eine neue WinAVR Version ?

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Vollständigen Quellcode. Vollständig!! Also alles was fürs übersetzen
benötigt wird, inklusive Makefile usw. Idealerweise nicht in Form von
20MB Plattenabzug, sondern soweit reduziert, dass nur noch der
problematische Teil in Form von ein paar Zeilen übrig bleibt.

Welcher Compiler? Also beispielsweise welches WinAVR.

Autor: Benedikt (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
Wenn es so einfach wäre, hätte ich das schon längst gemacht. Allerdings
darf ich den kompletten Code nicht veröffentlichen. Ich habe jetzt mal
alles weggelassen, außer den beiden Funktionen, das Problem existiert
weiterhin.

GCC Version: avr-gcc (GCC) 3.4.5
WinAVR Version vom 25.01.2006

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hat vielleicht einer die gcc.exe V4.1.1 schon fertig ?


Peter

Autor: A.K. (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Interessant.

Definiere mal uart_getchar() mit "unsigned" statt "unsigned char"
als Ergebnis. Macht in dieser Funktion Null Unterschied, weil's der
Compiler ohenehin so hält. Aber dafür bleibt der LCD-Routine der Frame
erspart.

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mit unsigned int oder nur unsigned wird der Code um 46Bytes kleiner und
der ganze Mist ist weg.
Aber warum ist das so ? Kann mir das jemand erklären ?

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Auch interessant:
Original Code mit -O3 compiliert: keine lokalen Variablen und
der Compiler inlined automatisch.

Autor: Karl heinz Buchegger (kbucheg)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> und der ganze Mist ist weg.

Ich nehme an, mit Mist meinst du die 1 lokale Variable die
nach der Optimierung übrig geblieben ist und deretwegen
im Funktionsprolog der Stackpointer korrigiert wird.

> Aber warum ist das so ? Kann mir das jemand erklären ?
Ist nicht ganz durchsichtig warum. Ich denke es könnte
daran liegen, dass automatisches inlinen bei einer Optimierungs-
stufe Os ausgeschaltet ist. Normalerweise macht inlinen den
Code größer und Os hat sich ja auf die Fahnen geheftet, möglichst
kleinen Code zu produzieren. In deinem Fall ist es aber umgekehrt,
da das inlinen Optimierungsmöglichkeiten eröffnet, die letztlich
zum Wegfall der 1nen übriggebliebenen lokalen Variablen eröffnet
und damit den ganze Stackpointer Kram unnötig macht. Man darf
halt nicht vergessen, dass Optimierungsstufen auf Heuristiken
beruhen. Es ist ja nicht so, dass der Compiler bei Os einmal
mit Auto-Inlining compiliert und einmal ohne und schaut was kleiner
ist.

Das erklärt aber nicht den Unterschied zwischen unsigned int und
unsigned char. Der ist mir auch noch ein Rätsel.

Autor: Jörg Wunsch (dl8dtl) (Moderator) Benutzerseite
Datum:
Angehängte Dateien:
  • lcd.s (1,17 KB, 108 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
> Das erklärt aber nicht den Unterschied zwischen unsigned int und
> unsigned char.

Vermutung: unsigned char wird nach integer promotion rules zuerst
zu `int' erweitert und erst von dort ggf. nach unsigned int.

Im Anhang übrigens der Code, der der GCC 4.1.0 daraus erzeugt
(mit den Werten aus dem Makefile, nur -g der Übersichtlichkeit
halber entfernt).

Sieht besser aus als 3.4.x, würde ich mal sagen.

Autor: Roland Schmidt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Reicht es aus, avrgcc411.zip in den WinAVR Ordner zu entpacken ?
Ich habe es mal gemacht, und es scheint zu funktionieren.
Es hat sich echt einiges geändert, die meisten Programme werden damit
etwas kleiner.

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

Bewertung
0 lesenswert
nicht lesenswert
> Es hat sich echt einiges geändert, die meisten Programme
> werden damit etwas kleiner.

Sach ich doch.  Im Durchschnitt ist die Optimierung beim AVR mit
dieser Version besser als mit den 3.x-ern.  Sicher findest du
allemal pathologische Fälle, wo der 3.x-er GCC besseren Code
erzeugt hat, aber in der realen Welt ist 4.1.x wirklich ein
Fortschritt (nachdem zuvor die 3er Versionen bezüglich des
AVR-Targets, das ja nicht gerade GCC-Mainstream ist, graduell
leicht schlechter geworden waren).

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich hab die 4.1.1 ausprobiert.

Bei vielen Projekten kriegt man tatsächlich eine ganz leichte
Reduzierung (1..2%).

Nur mein Jumbo-LED Beispiel wird dafür gleich 7% größer.


Allerdings erhalte ich nun immer folgende 2 Warnungen:

C:\DOKUME~1\danni\LOKALE~1\Temp/cc6naaaa.s:69: Warning: expression
dangerous with linker stubs
C:\DOKUME~1\danni\LOKALE~1\Temp/cc6naaaa.s:70: Warning: expression
dangerous with linker stubs


Da scheint also irgendwas noch nicht ganz astrein zu sein, weshalb der
WINAVR immer noch die alte 3.4.6. Version benutzt.
So schlimm sind ja die 1..2% mehr Code nun auch nicht.


Peter

Autor: Benedikt (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einige der Warnungen sind ganz sinnvoll. So erzeugt 4.1.1 z.B. Warnungen
wenn man pointer mit unterschiedlichen Vorzeichen übergibt.

Es gibt nichts schlimmeres als ein Compiler bei dem standardmäßig die
Warnungen fast alle abgeschaltet sind. Eine Klammer hinter einem
Funktionsaufruf vergessen, und man wundert sich warum nichts geht.
WinAVR gibt bei sowas (zum Glück) eine Warnung aus.

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

Bewertung
0 lesenswert
nicht lesenswert
> Allerdings erhalte ich nun immer folgende 2 Warnungen:

> Warning: expression dangerous with linker stubs

Das wäre mal interessant, dass du dir die Stelle in den
Assemblerdateien dazu ansiehst.  Dazu musst du über alle
Einzelschritte gehen, also statt mit -c von .c über eine temporäre
Assemblerdatei nach .o zuerst mit -S von .c nach .s (generierter
Assemblercode des Compilers) gehen und dann auf diese Datei nochmal
den avr-as ansetzen.

Das hat übrigens überhaupt nichts mit GCC 4.1.x zu tun, sondern das
kommt von den linker stubs, die für den Support der ATmega256x
eingebaut worden sind.  Der Patch ist derzeit noch experimentell,
AtmanAVR hat ihn aber bereits eingebaut.

Diskussionen darüber am besten auf avr-gcc-list (at nongnu.org)
führen, dort liest Björn Haase, der Autor des Patches, mit.

> Da scheint also irgendwas noch nicht ganz astrein zu sein, weshalb
> der WINAVR immer noch die alte 3.4.6. Version benutzt.

Quatsch mit Soße.

Beim letzten WinAVR war der GCC für Eric Weddington nicht zu schaffen,
beim nächsten wird 4.1.1 dabei sein -- und zwar mit dem
experimentellen ATmega256x-Patch.

Autor: Peter Dannegger (peda)
Datum:
Angehängte Dateien:
  • MAIN.S (2,41 KB, 132 Downloads)

Bewertung
0 lesenswert
nicht lesenswert
@Jörg,

also die Warnungen kommen von diesen beiden Zeilen (48,49) in main.s:

        subi r30,lo8(-(gs(.L12)))
        sbci r31,hi8(-(gs(.L12)))


Warscheinlich erzeugt jede switch-Anweisung mit Sprungtabelle diese
Warnungen.

Da ich ja eh nie vorhabe, >=Mega128 einzusetzen, dürften die Warnungen
also belanglos sein.


Peter

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

Bewertung
0 lesenswert
nicht lesenswert
gs ist ein Operator, den Björn dafür neu eingeführt hat...
Ich kann mir vorstellen, was die Warnung bedeutet: bei dieser
Operation könnte es passieren, dass man eine 128-KB-Grenze
überschreitet.  In diesem Falle wäre man natürlich aufgeschmissen...

Wie geschrieben, wenn du das diskutieren willst, ist die
avr-gcc-list das Forum der Wahl.

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.