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


von Johann L. (gjlayde) Benutzerseite


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:
1
    3.4.6     4.3.0
2
--------------------
3
A   1158      1252
4
B   6490      7400
5
C   4020      4354
6
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
1
# 3.4.6
2
.L9:
3
  ...
4
  st   X+,  r24
5
  cp   r24, r25
6
  breq .L9
1
# 4.3.0
2
.L9:
3
  ...
4
  st    X,   r24  
5
  cp    r24, r25  
6
  brne  .L10  
7
  adiw  r26, 1  
8
  rjmp  .L9  
9
.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...

von Andreas K. (a-k)


Lesenswert?

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

von 900ss (900ss)


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.

von Andreas K. (a-k)


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.

von 900ss (900ss)


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.

von Johann L. (gjlayde) Benutzerseite


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.

von 900ss (900ss)


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.

von Andreas K. (a-k)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


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.

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


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.

von Santiago (Gast)


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?

von Johann L. (gjlayde) Benutzerseite


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
1
../../gcc-4.2.4/gcc/config/avr/libgcc.S: Assembler messages:
2
../../gcc-4.2.4/gcc/config/avr/libgcc.S:280: Error: illegal opcode movw for mcu avr3
3
../../gcc-4.2.4/gcc/config/avr/libgcc.S:282: Error: illegal opcode movw for mcu avr3
4
make[3]: *** [libgcc/avr35/_mulsi3.o] Fehler 1
5
make[3]: Leaving directory `~/gcc-4.2.4-obj-avr/gcc'

xgcc wrote
1
~/gcc-4.2.4-obj-avr> ./gcc/xgcc -Bgcc -v
2
Reading specs from gcc/specs
3
Target: avr
4
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
5
Thread model: single
6
gcc version 4.2.4

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

von Johann L. (gjlayde) Benutzerseite


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 :-(

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


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.

von Peter D. (peda)


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

von Oliver (Gast)


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

von Johann L. (gjlayde) Benutzerseite


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

von Andreas K. (a-k)


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.

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


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.

von Johann L. (gjlayde) Benutzerseite


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
1
-mmcu=atmega8 
2
-Os
3
-S -save-temps -dp -fverbose-asm 
4
-fno-keep-inline-functions -fno-common
5
-W -Wall -Wstrict-prototypes -Wunused -Wextra

Für dieses Projekt sagt avr-size für .text:
1
avr-gcc 4.2.2: 4320
2
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
1
config.c:81: warning: initialized field overwritten
2
config.c:81: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.a')
3
config.c:82: warning: initialized field overwritten
4
config.c:82: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.b')
5
config.c:83: warning: initialized field overwritten
6
config.c:83: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.c_d')
7
config.c:84: warning: initialized field overwritten
8
config.c:84: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.e')
9
config.c:85: warning: missing initializer
10
config.c:85: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.nixie_bright.id')
11
config.c:86: warning: initialized field overwritten
12
config.c:86: warning: (near initialization for 'eeprom_defaults.<anonymous>.<anonymous>.nixie_bright')

Der Initializer wird richtig compilert und ist gegeben durch
1
eeprom_t eeprom;
2
3
const eeprom_t eeprom_defaults PROGMEM =
4
{
5
  .config_id = 4,      // 20kHz IRQ-Last
6
  .nixie = {
7
    .power_on     = 1,
8
    .volt         = 6, // ca. 162 V
9
    .change_100ms = 5
10
  },
11
  {{
12
    .a.id   = 0, .a.max   = 100,
13
    .b.id   = 5, .b.max   = 100,
14
    .c_d.id = 5, .c_d.max = 100,
15
    .e.id   = 0, .e.max   = 9,
16
    .nixie_bright.max = NIXIE_BRIGHT,
17
    .nixie_bright.id  = 5 // von 10
18
  }}
19
};

und eeprom_t
1
typedef struct 
2
{
3
  uint8_t max, id; // duty = 0..max
4
} eepwm_t;
5
6
typedef struct
7
{
8
  uint8_t config_id;
9
  
10
  struct
11
  {
12
    uint8_t power_on;
13
    uint8_t volt;
14
    uint8_t change_100ms;
15
  } nixie;
16
  
17
  union
18
  {
19
    // nixie.max: aktuelle Helligkeit: 0..bright.max
20
    struct
21
    {
22
      eepwm_t a, b, c_d, e; 
23
      eepwm_t nixie_bright;
24
    };
25
    eepwm_t pwm[5];
26
  };
27
} eeprom_t;
28
29
extern eeprom_t eeprom;

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

funktioniert auch nicht.

von Andreas K. (a-k)


Lesenswert?

Ich habe das mal ein bischen eingedampft. Mit
1
typedef struct 
2
{
3
  char max, id;
4
} eepwm_t;
5
6
typedef struct
7
{
8
  union
9
  {
10
    eepwm_t a; 
11
  };
12
} eeprom_t;
tritt die Warnung bei
1
const eeprom_t eeprom_defaults =
2
{
3
  {
4
    .a.id  = 0,
5
    .a.max = 100,
6
  }
7
};
noch auf, bei
1
const eeprom_t eeprom_defaults =
2
{
3
  { .a = {
4
    .id  = 0,
5
    .max = 100,
6
  }}
7
};
jedoch nicht mehr (V4.3.0).

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ok, aber
1
 .a = {.id = *, .max = * },
2
 .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?

von Andreas K. (a-k)


Lesenswert?

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

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ok, hab inzwischen ne Version die tut:
1
const eeprom_t eeprom_defaults PROGMEM =
2
{
3
  .config_id = 4,
4
  .nixie = {
5
    .power_on     = 1,
6
    .volt         = 6, // ca. 162 V
7
    .change_100ms = 5
8
  },
9
  {{
10
    .a   = { .id = 0, .max = 100},
11
    .b   = { .id = 5, .max = 100},
12
    .c_d = { .id = 5, .max = 100},
13
    .e   = { .id = 0, .max = 9},
14
    .nixie_bright = { .max = NIXIE_BRIGHT, // unused?
15
                      .id = 5 }// von 10
16
  }}
17
};

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

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


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.

von Andreas K. (a-k)


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.

von let (Gast)


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_".

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


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.

von Johann L. (gjlayde) Benutzerseite


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 :-(

von Andreas K. (a-k)


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.

von Peter D. (peda)


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

von Johann L. (gjlayde) Benutzerseite


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!

von Andreas K. (a-k)


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.

von Johann L. (gjlayde) Benutzerseite


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:
1
#include <avr/io.h>
2
3
unsigned char foo (void)
4
{
5
    unsigned char a=0;
6
    if (PIND & (1 << PD6)) a=1; 
7
    
8
    return a;
9
}

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
1
  .file  "foo.c"
2
  .arch atmega8
3
__SREG__ = 0x3f
4
__SP_H__ = 0x3e
5
__SP_L__ = 0x3d
6
__tmp_reg__ = 0
7
__zero_reg__ = 1
8
  .global __do_copy_data
9
  .global __do_clear_bss
10
 ;  GNU C version 3.4.6 (avr)
11
 ;   compiled by GNU C version 3.4.2 (mingw-special).
12
 ;  GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32702
13
 ;  options passed:  -fpreprocessed -mmcu=atmega8 -auxbase-strip -Os -W
14
 ;  -Wall -Winline -fverbose-asm -fno-keep-inline-functions
15
 ;  options enabled:  -feliminate-unused-debug-types -fdefer-pop
16
 ;  -fomit-frame-pointer -foptimize-sibling-calls -funit-at-a-time
17
 ;  -fcse-follow-jumps -fcse-skip-blocks -fexpensive-optimizations
18
 ;  -fthread-jumps -fstrength-reduce -fpeephole -fforce-mem -ffunction-cse
19
 ;  -fkeep-static-consts -fcaller-saves -freg-struct-return -fgcse
20
 ;  -fgcse-lm -fgcse-sm -fgcse-las -floop-optimize -fcrossjumping
21
 ;  -fif-conversion -fif-conversion2 -frerun-cse-after-loop
22
 ;  -frerun-loop-opt -fdelete-null-pointer-checks -fsched-interblock
23
 ;  -fsched-spec -fsched-stalled-insns -fsched-stalled-insns-dep
24
 ;  -fbranch-count-reg -freorder-functions -fcprop-registers -fcommon
25
 ;  -fverbose-asm -fregmove -foptimize-register-move -fargument-alias
26
 ;  -fstrict-aliasing -fmerge-constants -fzero-initialized-in-bss -fident
27
 ;  -fpeephole2 -fguess-branch-probability -fmath-errno -ftrapping-math
28
 ;  -minit-stack=__stack -mmcu=atmega8
29
30
  .text
31
.global  foo
32
  .type  foo, @function
33
foo:
34
/* prologue: frame size=0 */
35
/* prologue end (size=0) */
36
  ldi r24,lo8(0)   ;  a,   ;  8  *movqi/2  [length = 1]
37
  sbic 48-0x20,6   ; ,   ;  15  *sbix_branch  [length = 2]
38
  ldi r24,lo8(1)   ;  a,   ;  16  *movqi/2  [length = 1]
39
.L2:
40
  clr r25   ;  <result>   ;  29  zero_extendqihi2/1  [length = 1]
41
/* epilogue: frame size=0 */
42
  ret
43
/* epilogue end (size=1) */
44
/* function foo size 6 (5) */
45
  .size  foo, .-foo
46
/* File "foo.c": code    6 = 0x0006 (   5), prologues   0, epilogues   1 */

4.2.2 (4.3.0 ähnlich)
1
  .file  "foo.c"
2
__SREG__ = 0x3f
3
__SP_H__ = 0x3e
4
__SP_L__ = 0x3d
5
__tmp_reg__ = 0
6
__zero_reg__ = 1
7
  .global __do_copy_data
8
  .global __do_clear_bss
9
 ;  GNU C version 4.2.2 (WinAVR 20071221) (avr)
10
 ;   compiled by GNU C version 4.2.1-dw2 (mingw32-2).
11
 ;  GGC heuristics: --param ggc-min-expand=47 --param ggc-min-heapsize=32702
12
 ;  options passed:  -fpreprocessed -mmcu=atmega8 -auxbase-strip -Os -W
13
 ;  -Wall -Winline -fverbose-asm -fno-keep-inline-functions
14
 ;  options enabled:  -falign-loops -fargument-alias -fbranch-count-reg
15
 ;  -fcaller-saves -fcommon -fcprop-registers -fcrossjumping
16
 ;  -fcse-follow-jumps -fcse-skip-blocks -fdefer-pop -fearly-inlining
17
 ;  -feliminate-unused-debug-types -fexpensive-optimizations -ffunction-cse
18
 ;  -fgcse -fgcse-lm -fguess-branch-probability -fident -fif-conversion
19
 ;  -fif-conversion2 -finline-functions -finline-functions-called-once
20
 ;  -fipa-pure-const -fipa-reference -fipa-type-escape -fivopts
21
 ;  -fkeep-static-consts -fleading-underscore -fmath-errno
22
 ;  -fmerge-constants -fmove-loop-invariants -fomit-frame-pointer
23
 ;  -foptimize-register-move -foptimize-sibling-calls -fpeephole
24
 ;  -fpeephole2 -freg-struct-return -fregmove -freorder-functions
25
 ;  -frerun-cse-after-loop -fsched-interblock -fsched-spec
26
 ;  -fsched-stalled-insns-dep -fshow-column -fsplit-ivs-in-unroller
27
 ;  -fstrict-aliasing -fstrict-overflow -fthread-jumps -ftoplevel-reorder
28
 ;  -ftrapping-math -ftree-ccp -ftree-copy-prop -ftree-copyrename
29
 ;  -ftree-dce -ftree-dominator-opts -ftree-dse -ftree-fre -ftree-loop-im
30
 ;  -ftree-loop-ivcanon -ftree-loop-optimize -ftree-lrs -ftree-salias
31
 ;  -ftree-sink -ftree-sra -ftree-store-ccp -ftree-store-copy-prop
32
 ;  -ftree-ter -ftree-vect-loop-version -ftree-vrp -funit-at-a-time
33
 ;  -fverbose-asm -fzero-initialized-in-bss
34
35
 ;  Compiler executable checksum: 9c1f57ea9516abd07c34f2bc9c759a5a
36
37
  .text
38
.global  foo
39
  .type  foo, @function
40
foo:
41
/* prologue: frame size=0 */
42
/* prologue end (size=0) */
43
  in r24,48-0x20   ;  D.1505,   ;  11  *movqi/4  [length = 1]
44
  ldi r25,lo8(0)   ;  D.1505,   ;  34  *movqi/2  [length = 1]
45
  ldi r18,6   ; ,   ;  37  *lshrhi3_const/5  [length = 5]
46
1:  lsr r25   ;  D.1505
47
  ror r24   ;  D.1505
48
  dec r18   ; 
49
  brne 1b
50
  andi r24,lo8(1)   ;  tmp47,   ;  14  andqi3/2  [length = 1]
51
  ldi r25,lo8(0)   ;  <result>,   ;  36  *movqi/2  [length = 1]
52
/* epilogue: frame size=0 */
53
  ret
54
/* epilogue end (size=1) */
55
/* function foo size 10 (9) */
56
  .size  foo, .-foo
57
/* 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?

von Andreas K. (a-k)


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.

von Andreas K. (a-k)


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.

von Peter D. (peda)


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:
1
unsigned char foo (void)
2
{
3
  a6:   4e 9b           sbis    0x09, 6 ; 9
4
  a8:   02 c0           rjmp    .+4             ; 0xae <foo+0x8>
5
  aa:   82 e0           ldi     r24, 0x02       ; 2
6
  ac:   08 95           ret
7
  ae:   80 e0           ldi     r24, 0x00       ; 0
8
    unsigned char a=0;
9
    if (PIND & (1 << PD6)) a=2;
10
11
    return a;
12
}
13
  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

von Andreas K. (a-k)


Lesenswert?


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.