www.mikrocontroller.net

Forum: Compiler & IDEs avr-gcc: 3.4.6 contra 4.3.0


Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi,

bislang verwende ich avr-gcc 3.4.6 und bin im Gegensatz zu vielen 
anderen nicht immer gleich auf die neueste GCC-Version ungestiegen.

Da am GCC 4 schon ne Zeit lang gewerkelt wird, hab ich ihn mir mal 
besorgt und einen Blick drauf geworfen.

Meine Projekte übersetze ich mit -Os (optimize for size). Das mache m.E. 
den besten Code; -O2 macht grösseren Code bei nicht erkennbarem 
Geschwindigkeitsgewinn (zumindest in der 3.4.6).

Beim Übersetzen einiger Projekte ergeben sich folgende Größen mit 
avr-size:
    3.4.6     4.3.0
--------------------
A   1158      1252
B   6490      7400
C   4020      4354
D   4220      4756

Da war ich erst mal überrascht. Ich hätte Codegrößen erwartet, die in 
etwa gleich sind und nicht rund 10% größer.

Ein Blick ins .lst zeigt zunächst, daß 4.3.0 prologue_saves und 
epilogue_restores hinzulinkt, obwohl ich keine Libs nutze. Das 
verschwendet schon mal 110 Bytes. Die Funktionen werden nicht verwendet 
und auch mit -mno-call-prologues zugelinkt :-(

Der Rest an Mehrverbrauch ist Kleinkleckerei, hier ein Beispiel
# 3.4.6
.L9:
  ...
  st   X+,  r24
  cp   r24, r25
  breq .L9
# 4.3.0
.L9:
  ...
  st    X,   r24  
  cp    r24, r25  
  brne  .L10  
  adiw  r26, 1  
  rjmp  .L9  
.L10:

X wird danach nicht mehr gebraucht. Zweiteres braucht nicht nur mehr 
Code, sondern ist auch langsamer.

Die Arbeit in GCC 4 ist beachtlich, sie dürfte zum Großteil das 
Middleend betreffen, also Implementierung von SSA und von auf SSA 
basierenden maschinen-unabhängigen Optimierungen.

Genaugenommen sind Optimierungen jedoch nie M-unabhängig. Damit eine 
Transformation eine Optimierung ist, muss man den Code vorher und 
nachher bewerten können und dementsprechend fortfahren (oder spekulativ 
compilieren und von mehrere Varianten die beste wählen). Die 
Möglichkeiten zur Kostenbeschreibung sind im GCC leider nicht sehr 
ausgereift und werden in den M-unabhängigen Optimierungen wohl auch 
garnicht berücksichtigt (Regsiter-, Adress-, RTL-Kosten, etc). Der Code 
vom 4.3.0 spart zB im letzten Schleifendurchlauf eine Addition (denkt 
er); die Addition würde aber ohnehin in einem post-increment absorbiert.

Vorerst bleib's also beim guten, alten avr-gcc 3.4.6. Zumal der avr-gcc 
4.3.0 wegen eines bugs in den binutils unter linux die Generierung 
verweigert...

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Einen ungepatchen 4.3.0 sollte man ohnehin keinesfalls verwenden. Sind 
ein paar sehr üble Bugs drin.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:
> Einen ungepatchen 4.3.0 sollte man ohnehin keinesfalls verwenden. Sind
> ein paar sehr üble Bugs drin.

In der WinAVR080512 auch noch? Das ist der erste "neue" WinAVR, der bei 
mir Code erzeugt, der nicht abschmiert. Sonst mußte ich immer ab 
WinAVR200712xx und abwärts nehmen.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
WinAVR ist eine andere Baustelle, da sind ja auch etliche Patches drin. 
Ich bezog mich hier ausdrücklich auf einen ungepatchten GCC, da der 
Initiator des Threads eher in Linux zu Hause sein dürfte.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:
> WinAVR ist eine andere Baustelle, da sind ja auch etliche Patches drin.

So bewandert in den Internas bin ich da leider nicht. :-(

> Ich bezog mich hier ausdrücklich auf einen ungepatchten GCC, da der

Nichts für ungut, aber einen ausdrücklichen Bezug konnte ich nicht 
entdecken, darum meine Frage. Danke für die Aufklärung.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:
> Ich bezog mich hier ausdrücklich auf einen ungepatchten GCC, da der
> Initiator des Threads eher in Linux zu Hause sein dürfte.

Zum Glück wohne ich nicht in einem Betriebssystem.

Den Test von oben habe ich mit WinAVR-20080512 (4.3.0) und 
WinAVR-20060421  (3.4.6) gemacht.

Autor: 900ss D. (900ss)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg-johann Lay wrote:
> Den Test von oben habe ich mit WinAVR-20080512 (4.3.0) und

Der hat allerdings einen ganz häßlichen Bug und der sollte auch nicht 
genutzt werden. Er wurde ja auch von der Download-Seite entfernt.

Edit  Oh Mist, da habe ich mich mit dem Datum versehen, wie Andreas 
unten schrieb. Sorry. Die Version ist die zuletzt erschienene und auch 
noch verfügbar. Die Vorgängerversionen hatte ich gemeint.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Es hat seit Anfang April einige WinAVRs der 4.3.0 Serie erwischt, aber 
die Version vom 12.5. ist noch verfügbar.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
900ss D. wrote:
> Georg-johann Lay wrote:
>> Den Test von oben habe ich mit WinAVR-20080512 (4.3.0) und
>
> Der hat allerdings einen ganz häßlichen Bug und der sollte auch nicht
> genutzt werden.

Wegen den zu erwartenden Bugs hab ich ja auch Jahre gewartet, um mal den 
GCC 4 überhaupt anzutesten. Meine Programme zum Laufen zu bringen hab 
ich erst garnicht versucht, weil ich momentan in der Verwendung der 4.x 
kein Vorteil sehe gegen 3.4.6 (Stabilität, Codegüte, Compilier-Zeit). 
Ich wollte wie gesagt erst mal nur die Code-Güte abchecken, was mit den 
Bugs wohl nichts zu tun hat.

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

Bewertung
0 lesenswert
nicht lesenswert
Georg-johann Lay wrote:

> Wegen den zu erwartenden Bugs hab ich ja auch Jahre gewartet, um mal den
> GCC 4 überhaupt anzutesten.

Nun hast du ausgerechnet 3 Monate zu lange gewartet. ;-)

Siehe auch: Beitrag "Re: Würde gerne Assembler in C umschreiben, aber ich blick's net"

GCC 4.x ist schon OK, aber für x == 3 ist er noch mächtig grün.

Autor: Santiago (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

ich bin ja letztens auch mit einem WinAVR-update auf die Nase gefallen.
Z.Zt. setze ich den vom 22.01.07 ein.

Gibt es ein neueres Paket, welches empfehlenswert wäre?
Oder lieber noch abwarten?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

> GCC 4.x ist schon OK, aber für x == 3 ist er noch mächtig grün.

Was muss ich denn bei der 4.2.4 beachten?

Ist der Fehler in libgcc.S oder in as? Kann ich einfach die avr35 aus 
den MULTILIB_OPTIONS in {SOURCE}/gcc/config/avr/t-avr rauswerfen? Die 
Targets bräucht ich eh net.

make wrote
../../gcc-4.2.4/gcc/config/avr/libgcc.S: Assembler messages:
../../gcc-4.2.4/gcc/config/avr/libgcc.S:280: Error: illegal opcode movw for mcu avr3
../../gcc-4.2.4/gcc/config/avr/libgcc.S:282: Error: illegal opcode movw for mcu avr3
make[3]: *** [libgcc/avr35/_mulsi3.o] Fehler 1
make[3]: Leaving directory `~/gcc-4.2.4-obj-avr/gcc'

xgcc wrote
~/gcc-4.2.4-obj-avr> ./gcc/xgcc -Bgcc -v
Reading specs from gcc/specs
Target: avr
Configured with: ../gcc-4.2.4/configure --prefix=/local/gcc-avr-4.2.4-install --enable-languages=c --disable-nls --program-prefix=avr- --target=avr
Thread model: single
gcc version 4.2.4

as wrote
~/gcc-4.2.4-obj-avr> ./gcc/as --version
GNU assembler 2.16.1
Copyright 2005 Free Software Foundation, Inc.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
...und welche WinAVR-Version muss ich nehmen für den gcc 4.2.4? Ich seh 
da nur das build-Datum, aber nirgendwo welche 
gcc/binutils/libc/mingw-Version man sich damit einfängt :-(

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

Bewertung
0 lesenswert
nicht lesenswert
Ich glaube, die avr35-Geschichte ist irgendein Ding, wo eine
bestimmte Version der binutils nur zu einer bestimmten GCC-Version
passt.  Genau habe ich das aber auch noch nicht recherchiert.

Sorry, keine Ahnung, welcher Compiler in den einzelnen WinAVR-Versionen
verbaut ist, aber ich würde mal vermuten, dass Eric das in die release
notes reinschreibt.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ja, den AVR-GCC 4.3.0 muß man erst mit einigen Optimierungsschaltern in 
die richtige Richtung schubsen:


-fno-inline-small-functions
-fno-split-wide-types
-fno-tree-scev-cprop
-Wl,--relax


Peter

Autor: Oliver (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>...und welche WinAVR-Version muss ich nehmen für den gcc 4.2.4?

WinAVR20071221 enthält avr-gcc 4.2.2, die 2008er dann wohl schon einen 
4.3er. 4.2.4 ist nicht dabei.

Oliver

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Könnt mir mal jemend erklären, wo die Vorteile von avr-gcc 4 sind? (Mal 
abgesehen davon, dass er einige Derivate unterstützt, die avr-gcc 3 noch 
nicht kannte und die ich net einsetzte).

Ein Vorteil wäre für mich zum Beispiel
1) dichterer Code (ist offenbar nicht der Fall)
2) stabiler (seh ich auch net)
3) andere, neue Leistungsmerkmale

Bei 3) kommt zunächst mal die Definition von ISRs in den Sinn. Auch 
diese Änderung ist mir nich nachvollziehbar. Wozu ändert man das 
User-Interface? Sowas macht dem Benutzer doch nur Arbeit, und neue 
Funktionalität bringt es nicht. Auch ISR() bildet immer noch auf 
Attribute "signal" und "interrupt" ab. Ich seh auch nicht, was an SIGNAL 
und INTERRUPT missverständlich sein soll (sofern man die Doku gelesen 
hatte)?

Das einzige was ich da als neu sehe ist ein Attribut "OS_task". Wozu ist 
das eigentlich? Dokumentiert scheint's mal net zu sein und nur eine 
nackte Funktion mit RET abzuschliessen.

Die Arbeit im AVR-Backend betrifft neue Derivate (bzw. Cores) sowie die 
Umstellung von Prädikaten und Constraints auf RTL.

Die Arbeit im Middleend zielt m.E. in erster Linie auf konkurrierende 
32-Bit-Compiler für i386-Derivate, arm und ppc. Für AVR dürften viele 
dieser Optimierungen wie zB für SIMD ins Leere laufen...

Bitte versteht das net falsch. Es geht nicht darum, an GCC rumzumäkeln 
oder die Neuerungen schlecht zu reden. Viele der Arbeiten bringen GCC 
kanz klar weiter und/oder waren seit langem überfällig, und viel an 
Aufräumarbeiten und an (Internals-)Dokumentation bleibt zu tun (und wird 
hoffentlich auch mal getan). Jedoch sehe ich wie gesagt nicht die 
Vorteile für mich als Anwender von avr-gcc. Und es wird ja noch erlaubt 
sein, das alles kritisch zu hinterfragen und dass man net gleich schräg 
angeschaut wird, weil man nicht immer das Allerneueste hat.

Georg-Johann

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wenn du AVRs mit mehr als 128KB Speicher einsetzen willst, kommst du 
kaum um eine neuere Version herum. Und die XMegas erfordern wohl 4.3.

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

Bewertung
0 lesenswert
nicht lesenswert
Georg johann Lay wrote:

> Ein Vorteil wäre für mich zum Beispiel
> 1) dichterer Code (ist offenbar nicht der Fall)

Teilweise durchaus, je nach Optionen bis zu 10 % kleiner.

> 2) stabiler (seh ich auch net)

Doch, einige alte internal compiler errors sind mittlerweile
repariert.  Was soll sonst noch "instabil" sein?

> 3) andere, neue Leistungsmerkmale

Einige, kannst du sicher in GCC's Release-Notes nachlesen.

> Bei 3) kommt zunächst mal die Definition von ISRs in den Sinn.

Hat nichts mit dem Compiler zu tun, ist rein Sache der avr-libc.
Die läuft mit beiden Compilerversionen -- zumindest ist sie so
ausgelegt, allerdings wird sie sicher kaum noch von uns gegen
GCC 3.x getestet.  Warum sollte ich mir noch einen veralteten
Compiler antun?

> Auch
> diese Änderung ist mir nich nachvollziehbar. Wozu ändert man das
> User-Interface?

Du hast ja auch die vielen Supportanfragen wegen der missglückten
Benutzung von INTERRUPT() nicht bearbeiten müssen.  Wir schon.  Das
Ding war einfach mal ein kompletter Fehl-Name.

> Das einzige was ich da als neu sehe ist ein Attribut "OS_task". Wozu ist
> das eigentlich?

Und noch OS_main.  Sie lösen einen ziemlich schrägen Hack ab, den
der frühere Compiler hatte und der zu einer Sonderbehandlung des
Namens "main" führte, die vom C-Standard so nicht abgedeckt war.
Die Lösung mit OS_task/OS_main ist das, wie es wohl hätte von
Beginn an sein sollen.

> Und es wird ja noch erlaubt
> sein, das alles kritisch zu hinterfragen und dass man net gleich schräg
> angeschaut wird, weil man nicht immer das Allerneueste hat.

Ja, kannst du.  Du darfst eben nur nicht ewig Support für die alten
Tools erwarten.  Bugs werden bei GCC 3.x ganz sicher keine mehr
gefixt, und auch für avr-libc-1.4 haben wir mittlerweile das
Bugfixing eingestellt.  "stable" ist 1.6.x.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, ich bin mal mutig und lass die 4.2.2 (WinAVR-20071221) auf ein 
Projekt los...

Jörg Wunsch wrote:
> Georg johann Lay wrote:
>
>> Ein Vorteil wäre für mich zum Beispiel
>> 1) dichterer Code (ist offenbar nicht der Fall)
>
> Teilweise durchaus, je nach Optionen bis zu 10 % kleiner.

Würdest Du mir diese verraten?

Ich verwende avr-gcc momentan mit den Optionen
-mmcu=atmega8 
-Os
-S -save-temps -dp -fverbose-asm 
-fno-keep-inline-functions -fno-common
-W -Wall -Wstrict-prototypes -Wunused -Wextra

Für dieses Projekt sagt avr-size für .text:
avr-gcc 4.2.2: 4320
avr-gcc 3.4.6: 4210

wobei ich den alten Compiler ohne -Wextra fahre.

Jörg Wunsch wrote:
> Du darfst eben nur nicht ewig Support für die alten
> Tools erwarten.

Ok, dann mal ne Frage zu ner neuen Warning bei den neuen Tools :-) Ich 
progge in GNU-C
config.c:81: warning: initialized field overwritten
config.c:81: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.a')
config.c:82: warning: initialized field overwritten
config.c:82: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.b')
config.c:83: warning: initialized field overwritten
config.c:83: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.c_d')
config.c:84: warning: initialized field overwritten
config.c:84: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.e')
config.c:85: warning: missing initializer
config.c:85: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.nixie_bright.id')
config.c:86: warning: initialized field overwritten
config.c:86: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.nixie_bright')

Der Initializer wird richtig compilert und ist gegeben durch
eeprom_t eeprom;

const eeprom_t eeprom_defaults PROGMEM =
{
  .config_id = 4,      // 20kHz IRQ-Last
  .nixie = {
    .power_on     = 1,
    .volt         = 6, // ca. 162 V
    .change_100ms = 5
  },
  {{
    .a.id   = 0, .a.max   = 100,
    .b.id   = 5, .b.max   = 100,
    .c_d.id = 5, .c_d.max = 100,
    .e.id   = 0, .e.max   = 9,
    .nixie_bright.max = NIXIE_BRIGHT,
    .nixie_bright.id  = 5 // von 10
  }}
};

und eeprom_t
typedef struct 
{
  uint8_t max, id; // duty = 0..max
} eepwm_t;

typedef struct
{
  uint8_t config_id;
  
  struct
  {
    uint8_t power_on;
    uint8_t volt;
    uint8_t change_100ms;
  } nixie;
  
  union
  {
    // nixie.max: aktuelle Helligkeit: 0..bright.max
    struct
    {
      eepwm_t a, b, c_d, e; 
      eepwm_t nixie_bright;
    };
    eepwm_t pwm[5];
  };
} eeprom_t;

extern eeprom_t eeprom;

Wie muss ich den Initializer hinschreiben?
 .a = {.id = *, .max = * },
 .b = {.id = *, .max = * }, ...

funktioniert auch nicht.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe das mal ein bischen eingedampft. Mit
typedef struct 
{
  char max, id;
} eepwm_t;

typedef struct
{
  union
  {
    eepwm_t a; 
  };
} eeprom_t;
tritt die Warnung bei
const eeprom_t eeprom_defaults =
{
  {
    .a.id  = 0,
    .a.max = 100,
  }
};
noch auf, bei
const eeprom_t eeprom_defaults =
{
  { .a = {
    .id  = 0,
    .max = 100,
  }}
};
jedoch nicht mehr (V4.3.0).

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, aber
 .a = {.id = *, .max = * },
 .b = {.id = *, .max = * }, ...

funktioniert wie gesagt nicht, es gibt sogar eine error auf die Mütze 
von gcc, was ich nun überhaupt net raffe. Eigentlich sollte letztere 
Formulierung äquivalent zum Ausgangsausdruck sein?

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dann rück doch mal diese zweite nicht funktionierende Version raus.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, hab inzwischen ne Version die tut:
const eeprom_t eeprom_defaults PROGMEM =
{
  .config_id = 4,
  .nixie = {
    .power_on     = 1,
    .volt         = 6, // ca. 162 V
    .change_100ms = 5
  },
  {{
    .a   = { .id = 0, .max = 100},
    .b   = { .id = 5, .max = 100},
    .c_d = { .id = 5, .max = 100},
    .e   = { .id = 0, .max = 9},
    .nixie_bright = { .max = NIXIE_BRIGHT, // unused?
                      .id = 5 }// von 10
  }}
};

Die ursprünglichen Warnungen versteh ich aber immer noch net, ist aber 
net so wichtig wenn's ja so geht.

Bleibt nur noch das Lüften von Jörgs geheimen gcc-Schaltern. Bin echt 
mal gestpannt.

Immerhin läuft die mit 4.2.2 übersetzte Anwendung :-)

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

Bewertung
0 lesenswert
nicht lesenswert
Georg johann Lay wrote:

> Bleibt nur noch das Lüften von Jörgs geheimen gcc-Schaltern. Bin echt
> mal gestpannt.

Nö, nichts ist geheim.  Wird man wohl nur durch Vergleich der
beiden Compilate machen können.

Ich schrob ja auch nicht, dass GCC 4.x immer kleineren Code als
3.x erzeugen würde, aber ich habe teilweise Einsparungen bis zu 10 %
gesehen.  Das war allerdings bei relativ komplexen Projekten.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg johann Lay wrote:

> Die ursprünglichen Warnungen versteh ich aber immer noch net,

Der Compiler will damit sagen, dass er nach .a.id = 0, die Komponente 
"a" als bereits initialisiert ansieht und folglich .a.max = 100 die 
gleiche Komponente "a" nochmal initialisiert.

Dem ist zwar nicht so, aber stell dir mal vor was für ein Sudoku der 
Compiler lösen müsste, um so einen Sachverhalt bei zig verschachtelten 
Unions und wirr durcheinander erfolgenden Initialisierung immer 100% 
korrekt aufzulösen ohne eine mögliche Fehlerquelle und damit Warnung zu 
übersehen. Also hat sich jemand dazu entschlossen, eher auf der 
vorsichtigen Seite zu agieren.

Inwieweit das nun ein Fehler im Compiler ist, oder der ihn störende 
Quellcode nicht C99 entspricht, vermag ich nicht zu sagen. Der Standard 
scheint in dieser Tiefe auch nichts dazu herzugeben.

Jedenfalls entspricht die funktionierende Variante eher dem 
Verschachtelungsprinzip der Struktur und macht es m.E. sowohl dem 
Compiler als auch dem Programmierer leichter verständlich.

Autor: let (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Mal auf die Schnelle:

12544 Bytes - GCC 4.2.2
13050 Bytes - GCC 4.3.0
11744 Bytes - GCC 4.3.0 mit den von Peda vorgeschlagenen Optionen

Das Programm enthält einige etwas größere switch-Blöcke. Die
Warnung wegen irgendwelcher, möglicherweise gefährlichen Sprünge
sind verschwunden.

PS: Die Namen der FUSE-Bits haben sich geändert. Sie beginnen jetzt
mit "FUSE_".

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

Bewertung
0 lesenswert
nicht lesenswert
let wrote:

> Die
> Warnung wegen irgendwelcher, möglicherweise gefährlichen Sprünge
> sind verschwunden.

Die sind eh' Kokolorus und nur aus Versehen wieder reingerutscht.

Sie sind nicht ganz Kokolorus, aber an der Stelle im Assembler
viel zu spät, und vor allem viel zu undifferenziert.  Wenn überhaupt,
müsste man sie irgendwo im Linker unterbringen, aber dann wäre einige
Arbeit an der Infrastruktur vonnöten, um Sprungtabellen irgendwie
gezielt ein Attribut verpassen zu können, dass diese zusammenhängend
im Speicher liegen müssen.

> PS: Die Namen der FUSE-Bits haben sich geändert. Sie beginnen jetzt
> mit "FUSE_".

Da gab es zu viele Doppeldeutigkeiten mit Namen von Registerbits.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hab nochmal den Vergleich gemacht mit den von Peter angegebenen Optionen 
für 4.3.0, übersetzt mit -Os. Die Quellen sind so geschrieben, dass sie 
für gcc gut verdaulich sind. Bibliotheken verwende ich keine, aussen 
Zugriff aufs EEPROM und n paar Ganzzahl-Operationen aus der libgcc2.

Ich bekomme folgende Zahlen:

4446 avr-gcc 4.3.0
4300 avr-gcc 4.2.2
4218 avr-gcc 3.4.6

Irgendwas mach ich da wohl falsch :-(

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Map Files erzeugen und mal sehen ob sich der Zuwachs gleichmässig 
verteilt oder ein besonders krasses Beispiel dabei ist. Oder irgendwas 
unerwünschtes aus der Lib gezogen wird. Die erwähnten Optionen sind ja 
auch nicht vom Himmel gefallen - bei 2 davon hatte ich ein kleines 
Beispiel gesehen und nach passenden Optionen gesucht.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg johann Lay wrote:

> Zugriff aufs EEPROM

Genau das wurde beim  4.3.0 äußerst umständlich über indirekten Call 
gelöst und erzeugt daher sehr viel Code.

Ich mach das eh immer über direkten Zugriff per IO-Register selber.
Dabei teste ich vorher, ob sich das Byte auch geändert hat und spare 
dann Schreibzyklen ein.


Peter

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:

> Map Files erzeugen und mal sehen ob sich der Zuwachs gleichmässig
> verteilt oder...

hmmm, im .map geht die size-Info irgendwie unter und ist auch schlecht 
zu greppen. Die Größen schau ich an mit avr-size oder avr-nm, sollte 
doch das gleiche ausgeben?

Der Mehrverbrauch ist Giesskannenartung und um so grösser, je grösser 
die Funktion ist. Ein paar kleinere Funktionen sind auch um einige Byte 
geschrumpft, aber insgesamt ergibt sich das gesagte Bild.

Unnötig zugelinkt wird nix, ausser _epilogue_restores_  und 
_prologue_saves_ in der 4.3.0, die nicht verwendet werden (siehe 
oben).

Beitrag "avr-gcc: 3.4.6 contra 4.3.0"

Peter Dannegger wrote:
> Georg johann Lay wrote:
>
>> Zugriff aufs EEPROM
>
> Genau das wurde beim  4.3.0 äußerst umständlich über indirekten Call
> gelöst und erzeugt daher sehr viel Code.
>
> Ich mach das eh immer über direkten Zugriff per IO-Register selber.
> Dabei teste ich vorher, ob sich das Byte auch geändert hat und spare
> dann Schreibzyklen ein.

Ok. **kopfkratz** warum da rumgeschraubt wurde muss man nicht wirklich 
verstehen, oder? Warum braucht's da einen icall?

== EDIT ==

**ARGL** jetzt seh ich auch, wer für das Prolog/Epilog-Zeug 
verantworlich ist. Ich hatte nur nach dem Symbol bzw. der Startadresse 
gesucht und nicht erwartet, dass da mitten rein gejumpt wird!

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Georg johann Lay wrote:

> Ok. **kopfkratz** warum da rumgeschraubt wurde muss man nicht wirklich
> verstehen, oder? Warum braucht's da einen icall?

Ich hatte das so verstanden, dass man in einer Library wie der avr-libc 
modellabhängige Funktionen untergebracht hat, ohne die Library für jedes 
sich unterschiedliche verhaltende Modell getrennt zu kompilieren und 
auszuliefern.

Sowas funktioniert nur gut wenn man alle modellabhängigen Funktionen 
inline im Include-File unterbringt oder wenn man die Library für jedes 
sich unterschiedliche verhaltende Modell separat übersetzt.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:
> Map Files erzeugen und mal sehen ob sich der Zuwachs gleichmässig
> verteilt oder ein besonders krasses Beispiel dabei ist.

Hi, hier mal ein Beispiel (für avr-gcc 4.2.2) mit folgender C-Quelle:
#include <avr/io.h>

unsigned char foo (void)
{
    unsigned char a=0;
    if (PIND & (1 << PD6)) a=1; 
    
    return a;
}

Eigentlich keine große Aktion. Es ergeben sich folgende .s (aus .i), die 
ich hier mal ganz poste, damit man die Optionen sieht.

3.4.6
  .file  "foo.c"
  .arch atmega8
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
  .global __do_copy_data
  .global __do_clear_bss
 ;  GNU C version 3.4.6 (avr)
 ;   compiled by GNU C version 3.4.2 (mingw-special).
 ;  GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32702
 ;  options passed:  -fpreprocessed -mmcu=atmega8 -auxbase-strip -Os -W
 ;  -Wall -Winline -fverbose-asm -fno-keep-inline-functions
 ;  options enabled:  -feliminate-unused-debug-types -fdefer-pop
 ;  -fomit-frame-pointer -foptimize-sibling-calls -funit-at-a-time
 ;  -fcse-follow-jumps -fcse-skip-blocks -fexpensive-optimizations
 ;  -fthread-jumps -fstrength-reduce -fpeephole -fforce-mem -ffunction-cse
 ;  -fkeep-static-consts -fcaller-saves -freg-struct-return -fgcse
 ;  -fgcse-lm -fgcse-sm -fgcse-las -floop-optimize -fcrossjumping
 ;  -fif-conversion -fif-conversion2 -frerun-cse-after-loop
 ;  -frerun-loop-opt -fdelete-null-pointer-checks -fsched-interblock
 ;  -fsched-spec -fsched-stalled-insns -fsched-stalled-insns-dep
 ;  -fbranch-count-reg -freorder-functions -fcprop-registers -fcommon
 ;  -fverbose-asm -fregmove -foptimize-register-move -fargument-alias
 ;  -fstrict-aliasing -fmerge-constants -fzero-initialized-in-bss -fident
 ;  -fpeephole2 -fguess-branch-probability -fmath-errno -ftrapping-math
 ;  -minit-stack=__stack -mmcu=atmega8

  .text
.global  foo
  .type  foo, @function
foo:
/* prologue: frame size=0 */
/* prologue end (size=0) */
  ldi r24,lo8(0)   ;  a,   ;  8  *movqi/2  [length = 1]
  sbic 48-0x20,6   ; ,   ;  15  *sbix_branch  [length = 2]
  ldi r24,lo8(1)   ;  a,   ;  16  *movqi/2  [length = 1]
.L2:
  clr r25   ;  <result>   ;  29  zero_extendqihi2/1  [length = 1]
/* epilogue: frame size=0 */
  ret
/* epilogue end (size=1) */
/* function foo size 6 (5) */
  .size  foo, .-foo
/* File "foo.c": code    6 = 0x0006 (   5), prologues   0, epilogues   1 */

4.2.2 (4.3.0 ähnlich)
  .file  "foo.c"
__SREG__ = 0x3f
__SP_H__ = 0x3e
__SP_L__ = 0x3d
__tmp_reg__ = 0
__zero_reg__ = 1
  .global __do_copy_data
  .global __do_clear_bss
 ;  GNU C version 4.2.2 (WinAVR 20071221) (avr)
 ;   compiled by GNU C version 4.2.1-dw2 (mingw32-2).
 ;  GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32702
 ;  options passed:  -fpreprocessed -mmcu=atmega8 -auxbase-strip -Os -W
 ;  -Wall -Winline -fverbose-asm -fno-keep-inline-functions
 ;  options enabled:  -falign-loops -fargument-alias -fbranch-count-reg
 ;  -fcaller-saves -fcommon -fcprop-registers -fcrossjumping
 ;  -fcse-follow-jumps -fcse-skip-blocks -fdefer-pop -fearly-inlining
 ;  -feliminate-unused-debug-types -fexpensive-optimizations -ffunction-cse
 ;  -fgcse -fgcse-lm -fguess-branch-probability -fident -fif-conversion
 ;  -fif-conversion2 -finline-functions -finline-functions-called-once
 ;  -fipa-pure-const -fipa-reference -fipa-type-escape -fivopts
 ;  -fkeep-static-consts -fleading-underscore -fmath-errno
 ;  -fmerge-constants -fmove-loop-invariants -fomit-frame-pointer
 ;  -foptimize-register-move -foptimize-sibling-calls -fpeephole
 ;  -fpeephole2 -freg-struct-return -fregmove -freorder-functions
 ;  -frerun-cse-after-loop -fsched-interblock -fsched-spec
 ;  -fsched-stalled-insns-dep -fshow-column -fsplit-ivs-in-unroller
 ;  -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftoplevel-reorder
 ;  -ftrapping-math -ftree-ccp -ftree-copy-prop -ftree-copyrename
 ;  -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im
 ;  -ftree-loop-ivcanon -ftree-loop-optimize -ftree-lrs -ftree-salias
 ;  -ftree-sink -ftree-sra -ftree-store-ccp -ftree-store-copy-prop
 ;  -ftree-ter -ftree-vect-loop-version -ftree-vrp -funit-at-a-time
 ;  -fverbose-asm -fzero-initialized-in-bss

 ;  Compiler executable checksum: 9c1f57ea9516abd07c34f2bc9c759a5a

  .text
.global  foo
  .type  foo, @function
foo:
/* prologue: frame size=0 */
/* prologue end (size=0) */
  in r24,48-0x20   ;  D.1505,   ;  11  *movqi/4  [length = 1]
  ldi r25,lo8(0)   ;  D.1505,   ;  34  *movqi/2  [length = 1]
  ldi r18,6   ; ,   ;  37  *lshrhi3_const/5  [length = 5]
1:  lsr r25   ;  D.1505
  ror r24   ;  D.1505
  dec r18   ; 
  brne 1b
  andi r24,lo8(1)   ;  tmp47,   ;  14  andqi3/2  [length = 1]
  ldi r25,lo8(0)   ;  <result>,   ;  36  *movqi/2  [length = 1]
/* epilogue: frame size=0 */
  ret
/* epilogue end (size=1) */
/* function foo size 10 (9) */
  .size  foo, .-foo
/* File "foo.c": code   10 = 0x000a (   9), prologues   0, epilogues   1 */

Der baut da tatsächlich ne Schleife ein! (lshrhi3, ein 16-Bit-Shift um 6 
nach rechts). Das Verhalten seh ich auch im Programm-Kontext, also in 
vivo. Es bringt mehr Code und ist deutlich langsamer. Zudem werden mehr 
REGs gebraucht.

Offenbar kommt das von den neuen Optimierungen. Kann man ihm sowas 
irgendwie abgewöhnen?

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Der ist interessant. Offenbar eine Folge von Optimierung für moderne 
high performance Architekturen, bei denen es fast immer lohnend ist, 
Sprungbefehle durch Rechnung zu ersetzen. Pech, dass AVRs besser 
springen als shiften können.

Es gibt dazu zwar ein paar Flags wie -fno-if-conversion, aber die 
scheinen hier nicht zu greifen.

Sieht nach einem Kandidat für Bugzilla aus, wenn's da nicht schon drin 
ist.

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Schätze es könnte sich lohnen gcc/tree-ssa-ifcombine.c abschaltbar zu 
machen. Alles mögliche an Optimierungen kann man per Switches 
abschalten, aber den pass leider nicht.

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Andreas Kaiser wrote:
> Der ist interessant. Offenbar eine Folge von Optimierung für moderne
> high performance Architekturen, bei denen es fast immer lohnend ist,
> Sprungbefehle durch Rechnung zu ersetzen. Pech, dass AVRs besser
> springen als shiften können.

Ja, diese Disoptimisation ist wirklich heftig, scheint aber nur bei den 
Returnwerten 0/1 aufzutreten.

Bei 0/2 macht er die übliche Disoptimisation, also nur 2 überflüssige 
Befehle:

unsigned char foo (void)
{
  a6:   4e 9b           sbis    0x09, 6 ; 9
  a8:   02 c0           rjmp    .+4             ; 0xae <foo+0x8>
  aa:   82 e0           ldi     r24, 0x02       ; 2
  ac:   08 95           ret
  ae:   80 e0           ldi     r24, 0x00       ; 0
    unsigned char a=0;
    if (PIND & (1 << PD6)) a=2;

    return a;
}
  b0:   08 95           ret


Wäre schön, wenn man ihm die bei dieser Gelegenheit gleich mit 
abgewöhnen könnte.

Es ärgert schon, wenn man den else-Zweig rausoptimiert und er ihn dann 
aber wieder reinpappt.


Peter

Autor: Andreas K. (a-k)
Datum:

Bewertung
0 lesenswert
nicht lesenswert

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.