Forum: Compiler & IDEs erzeugter code von avrgcc ineffizient


von Jochen (Gast)


Lesenswert?

Hallo

Es wäre mir ja nicht aufgefallen, hätte ich nicht
das Oszilloskop laufen lassen.

folgende C-Code Zeile:

  loop_until_bit_is_set(CONTROL_IN, DATA_STROBE);

wird so übersetzt:

+0000020B:   B380        IN      R24,0x10         In from I/O location
+0000020C:   9580        COM     R24              One's complement
+0000020D:   FD80        SBRC    R24,0            Skip if bit in 
register cleared
+0000020E:   CFFC        RJMP    -0x0004          Relative jump

das sind 4 ops.
es geht auch mit 2en.

asm volatile (
  "sbis  0x10,4"    "\n\t"
  "rjmp  -0x0002"    "\n\t"
  ::
  );

und so sieht auch das Makro in iomacros.h aus.

Ich vermute dass er Codeoptimierer da irgendwie reinfuscht.

Kann mir jemand etwas genaueres darüber sagen?
Wie kann ich im asm block die obengenannten Konstanten
einbinden. (trotz avr-asm cookbook bekomme ich es nicht hin)

Wäre wirklich dankbar für Ratschläge und Hinweise.

Bye

von Notker (Gast)


Lesenswert?

Das ist schon recht seltsam, da der Assemblercode dieses Makros, wie du 
ja selbst festgestellt hast, in iomacros.h definiert ist. Und das 
Schlüsselwort volatile steht auch dabei, daher dürfte der Optimierer 
dort nichts herumdrehen.

Und du bist sicher, dass du dich nicht vertan hast? Schau dir mal die 
Stelle im AVR-Studio an, da kann man ja zwischen Assembler- und 
Sourcecode-Ansicht umschalten.

von Jochen (Gast)


Lesenswert?

Ja, das ist aus dem AVR-Studio entnommen.
Hier nochmal das Original.

516:            loop_until_bit_is_set(EPP_CONTROL_IN, EPP_DATA_STROBE);
+00000208:   B380        IN      R24,0x10         In from I/O location
+00000209:   9580        COM     R24              One's complement
+0000020A:   FD80        SBRC    R24,0            Skip if bit in 
register cleared
+0000020B:   CFFC        RJMP    -0x0004          Relative jump


Hier auch mal die Optionen vom Makefile:

#Hier definieren wir Einstellungen (Flags) für den Assembler,
  ASFLAGS = -Wa, -gstabs

#den Compiler
  CPFLAGS  = -g -Os -Wall -Wstrict-prototypes -Wa,-ahlms=$(<:.c=.lst)

#und den Linker
  LDFLAGS = -Wl,-Map=$(TRG).map,--cref


Es würde mich mal interessieren, ob andere auch diesen Code
von loop_until_bit_is_set() erhalten.

von Jochen (Gast)


Lesenswert?

Misst eigentlich wollte ich den oberen Beitrag nur einmal haben.

Naja.

Es kommt aber noch besser, mit Optimieroption -O0
kommt folgendes raus...

169:            loop_until_bit_is_set(EPP_CONTROL_IN, EPP_DATA_STROBE);
+000000DD:   91800030    LDS     R24,0x0030       Load direct from data 
space
+000000DF:   2799        CLR     R25              Exclusive OR
+000000E0:   9580        COM     R24              One's complement
+000000E1:   9590        COM     R25              One's complement
+000000E2:   7081        ANDI    R24,0x01         Logical AND with 
immediate
+000000E3:   7090        ANDI    R25,0x00         Logical AND with 
immediate
+000000E4:   9700        SBIW    R24,0x00         Subtract immediate 
from word
+000000E5:   F7B9        BRNE    +0x77            Branch if status flag 
cleared

das ist ja Wahnsinn.

von Jochen (Gast)


Lesenswert?

Vielleicht sollte ich noch dazu sagen, daß es für einen
Atmega128 (MCU = atmega128) kompiliert wurde.

von Notker (Gast)


Lesenswert?

Ich arbeite nun schon seit einiger Zeit mit dem avrgcc und bin von der 
Qualität des erzeugten Codes sehr überzeugt (im Gegensatz zu anderen 
handelsüblichen Compilern!). Daher habe ich diese Sache selbst mal 
überprüft, indem ich mit dem AVR-Studio mal Code unter die Lupe genommen 
habe, wo dieser Makro verwendet wurde.

Also ich kann das, was du hier schreibst absolut nicht nachvollziehen, 
bei mir stehen immer die Assemblerbefehle drin, die auch dort stehen 
sollen, nämlich die, die in iomacros.h definiert sind und sonst nichts! 
Wo soll auch der andere Code herkommen, der Compiler saugt sich sowas 
doch nicht aus den Fingern und bei Assemblercode, der mit dem 
Schlüsselwort "volatile" gekennzeichnet ist, dort mengt auch der 
Optimierer nichts herum, das kann man in jedem Lehrbuch nachlesen. 
Getestet habe ich dies mit avrgcc Version 3.02.

Sag mal, woher stammen denn die Beschreibungstexte hinter dem 
Assemblercode? Ist das neu im AVR-Studio Version 4? In Version 3 sieht 
das aber etwas anders aus.

Ich habe in anderen Foren schon einiges erlebt, wo Leute versucht haben, 
über die  Qualität des avrgcc herzuziehen. Solche Leute entpuppten sich 
dann aber stets als Mitarbeiter von Handelsfirmen, die kommerzielle 
Konkurrenzprodukte verkaufen oder es waren Leute, die scheinbar sonst 
irgendwie gesponsort wurden um solche Aussagen zu machen. Und deren 
Aussagen entpuppten sich bei genauerer Betrachtung stets recht schnell 
als heisse Luft.

Ich habe erst kürzlich die Testversion des ICCtiny von Imagecraft bei 
mir installiert, weil ich neugierig war, was so ein 200$-Produkt zu 
leisten vermag. Schon am ersten Tag hatte ich 2 heftige Compiler-Fehler, 
die bei einem ausgereiften Produkt niemals hätten vorkommen dürfen. 
Daraufhin hatte ich die Fehlerbeschreibung mit einem Beispielcode an 
Imagecraft gesendet, weil ich auf deren Antwort gespannt war. Das 
einzige, das ich bis heute zurückbekam war eine knappe Bestätigung über 
den Erhalt meiner Mail und das ist nun schon fast einen Monat her. Auf 
weitere Rückfragen erhielt ich keine Antwort! Dies will ich hier nun 
nicht mehr weiter kommentieren, solche Sachen die sprechen halt für 
sich.

Soweit meine 0.02$ zu diesem Thema.

Notker

von Jochen (Gast)


Lesenswert?

Also es scheint am avr-gcc 3.2 (ja 3.2!!!) zu liegen.
(2002-06-25_FREAKS.exe)

#include <io.h>
int main (void)
{
  loop_until_bit_is_set(PINA, 0);

}


mit 3.2 (eben FALSCH):

5:        int main (void)
6:        {
+00000052:   EFCF        SER     R28              Load immediate
+00000053:   E0DF        LDI     R29,0x0F         Load immediate
+00000054:   BFDE        OUT     0x3E,R29         Out to I/O location
+00000055:   BFCD        OUT     0x3D,R28         Out to I/O location
7:          loop_until_bit_is_set(PINA, 0);
+00000056:   B389        IN      R24,0x19         In from I/O location
+00000057:   9580        COM     R24              One's complement
+00000058:   FD80        SBRC    R24,0            Skip if bit in 
register cleared
+00000059:   CFFC        RJMP    -0x0004          Relative jump
9:        }

mit 3.02 (RICHTIG)
(avrgcc20011121a.exe)

5:        int main (void)
6:        {
+00000053:   EFCF        SER     R28              Load immediate
+00000054:   E0DF        LDI     R29,0x0F         Load immediate
+00000055:   BFDE        OUT     0x3E,R29         Out to I/O location
+00000056:   BFCD        OUT     0x3D,R28         Out to I/O location
7:          loop_until_bit_is_set(PINA, 0);
+00000057:   9BC8        SBIS    0x19,0           Skip if bit in I/O 
register set
+00000058:   CFFE        RJMP    -0x0002          Relative jump
9:        }
+00000059:   CFFF        RJMP    -0x0001          Relative jump


Aber die 3.02 Version unterstützt keinen ATmega128!!
Was soll ich machen?
Kann mir jemand helfen?

Jochen

von Notker (Gast)


Lesenswert?

Die Version 3.20 ist deutlich als Experimentalversion (=Alpha Stadium) 
gekennzeichnet! Aber dass hier so gravierende Mängel drin sind, hätte 
ich nicht gedacht.

Meiner Meinung nach müsste es aber auch möglich sein, die Version 3.02 
für diese neuen Mega-Typen zumindest bedingt nutzbar zu machen. Wenn man 
sich selbst eine Header-Datei bastelt, müsste es auch möglich sein, Code 
für einen anderen Typen für den Mega128 lauffähig zu bekommen. 
Allerdings werden wohl nicht alle Features des Mega128 nutzbar sein. 
Kommt halt drauf an, was du machen willst.

Notker

von mikki merten (Gast)


Lesenswert?

Ist ja im Prinzip kein Fehler, sondern nur nicht ganz optimaler Code. 
Das Problem sind ja der MEGA128 und der und alle anderen MEGA AVR mit 
I/O-Registern im Bereich > 60h. Dieses war ja ursprünglich garnicht so 
vorgesehen. Dieser ist auch nur mit entsprechenden Memory orientierten 
Befehlen erreichbar. Ebenso so wurden ja etliche Register aus dem 
SBIC/SBIS Bereich heraus verschoben. Man braucht sich nur mal die 
Header-Datei sfr_defs.h anzuschauen. Hier optimalen Code zu erzeugen, 
erfordert doch aufwendige Behandlung von Sonderfällen. Ganz nebenbei 
wird ja hier ATMEL der normalen AVR Architektur etwas untreu. Hier 
sollte man nicht auf die Arbeit anderer Leute schimpfen, sondern selber 
vielleicht Lösungen für diese Sonderfälle entwickeln, die zu optimalerem 
Code führen.

von Notker (Gast)


Lesenswert?

> Das Problem sind ja der MEGA128 und der und alle anderen MEGA AVR mit 
I/O-Registern im Bereich > 60h.

Die Adresse im Beispiel ist aber 0x10.

> Dieses war ja ursprünglich garnicht so vorgesehen. Dieser ist auch nur mit 
entsprechenden Memory orientierten Befehlen erreichbar.

Das trifft aber auf das obige Beispiel nicht zu.

> Hier sollte man nicht auf die Arbeit anderer Leute schimpfen, sondern selber 
vielleicht Lösungen für diese Sonderfälle entwickeln, die zu optimalerem Code 
führen.

Wie ich schon sagte, meine Meinung über den avrgcc ist eigentlich recht 
positiv. Aber diese Sache ist eindeutig ein Mangel, der korrigiert 
werden muss, da gibt es keine Diskussion. Wie schon gesagt, die Version 
3.20 ist ja auch eindeutig als Experimentalversion gekennzeichnet.

von mikki merten (Gast)


Lesenswert?

@Notker
Woher soll der Compiler denn ohne Ausnahmebhandlung denn wissen, dass 
der I/O Port PINx den im Bit-Testbereich liegt. Bei der 
Standardarchitektur war und ist dies ja der Fall.
Ich muss dir allerdings zustimmen das der AVRGCC für alle "Standard" 
AVRs recht vernünftigen und stabilen Code erzeugt.

von Jochen (Gast)


Lesenswert?

Erstmal Danke für die rege Teilnahme an diesem Problem.

Da die avrgcc 3.2 ja nicht nur die Codeerzeugung für den ATmega8 und 
ATmega128 betrifft, sondern auch wohl andere wie
zB. Atmega103 denke ich dass es sinnvoll ist, eine
Lösung zu finden, die diese Grenze berücksichtigt.
(wenn es daran liegt)

Werde mich mal daran versuchen, denke aber nicht dass ich es
hinbekomme, da mein Wissen über den gcc nicht besonders ist.

Hatte auch noch ein anderes Problem, nämlich dass der Compiler Code 
erzeugt hatte der mehr RAM verbraucht hatte als der Atmega128 her gab. 
(lag aber an meiner Fehleinschätzung)
Ist mir nicht aufgefallen, da der Compiler sich nicht
gemeldet hatte.


   text    data     bss     dec     hex filename
   1234      82    4527    5843    16d3 Prell.elf

data (82bytes) + bss (4527bytes) > 4096Bytes RAM

Naja jetzt läuft es mit nem kleineren array.


Wäre echt gut wenn man zu dem anderen Problem eine Lösung findet.

Außerdem finde es noch komisch dass er erst dass Complement bildet und 
dann auf bit_clear testet anstatt direkt auf bit_set.

von nolife (Gast)


Lesenswert?

Hi,
ich habe bis vor etwa einem Monat mit dem ICC programmiert, und
bin derzeit auf avr-gcc.
Die neueste Winavr version ist ausgezeichnet.

Ich habe das exakt gleiche (relative einfache) Programm von icc
nach gcc geportet.
Dabei sind etwa 1kb asm source und der rest in c.
Aufgefallen ist mir (das war das avrfreaks release, also die vorherige 
version 3.2) dass der code von anfang an schneller lief.
Wo ICC erst ab 500$ einen (in dem programm völlig ineffektiven) 
optimizer anbietet funktioniert der von avr umsonst und wirklich 
effizient.

der erzeugte code war um 30% kleiner als der vom ICC.

Die einzigen Nachteile des AVR die mir sind:
Größerer Programmieraufwand da der ICC mehr libraries etc hat.
Das debuggen des gcc codes im avrstudio geht nicht
 so gut wie das des ICC codes, zb kann man beim icc
 externe asm files wie ne weitere .c file singlesteppen,
 beim gcc wird das sehr unübersichtlich.
Man muss sich erst in die makefiles etc einarbeiten,
 das soll zwar glaube ich alles vereinfacht werden, also
 dass avrgcc sogar mit gui etc kommt, aber ich schätze es wird
 noch einige Zeit dauern bis der gcc auch so komfortabel wie
 ein kommerzieller Compiler wird, generell das größte
 Program das unixprogramme so an sich haben (denke ich).

Mein Fazit:
Er ist umsonst, er arbeitet effektiver und die neueste Version
ist gleich angenehm zu programmieren wie der ICC.
Und Support findet man beim weiter verbreiteten gcc auch einfacher als 
beim ICC oder einem anderen kommerziellen crosscompiler.

von Markus Burrer (Gast)


Lesenswert?

Eine "GUI" für den GCC gibt es doch mehr oder weniger schon. Schau Dir 
mal AVREdit an. Das ist die GCC Version von AVRfreaks mit einem Editor. 
Leider noch nicht ganz Bugfree

von Michael Bergmann (Gast)


Lesenswert?

Beim Umstieg von avrgcc 3.02 zu avrgcc 3.3 (WinAVR) bin ich ueber genau 
dieses loop_until_bit_is_set macro gestolpert.

Beim avrgcc 3.02 ist es in iomacro.h als asm-macro so definiert:
#define loop_until_bit_is_set(port, bit)    \
  _asm__ __volatile_ (        \
  "L_%=: " "sbis %0,%1" "\n\t"      \
    "rjmp L_%="        \
    : /* no outputs */      \
    : "I" ((uint8_t)(port-__SFR_OFFSET)),    \
      "I" ((uint8_t)(bit))      \
  )

Beim avrgcc 3.3 hingegen so:
#define bit_is_clear(sfr, bit) (~inb(sfr) & _BV(bit))
#define loop_until_bit_is_set(sfr, bit) do { } while (bit_is_clear(sfr, 
bit))

Das Problem liegt in dem bitweise Komplement in von inb(sfr) in dem 
bit_is_clear() Macro. Der Compiler denkt wohl, er muss erst alle Bits 
einlesen, um dann das Kompelement zu bilden und danach ein Bit zu 
maskieren. Als Lösung habe ich ein eigenes _loop_until_bit_is_set 
geschrieben, welche das bitweise invertieren vermeidet:

#define _loop_until_bit_is_set(port, bit) { while (!bit_is_set((port), 
(bit))); }

Bei dieser Version verwendet der gcc den "skip on bit" Befehl 
(Compileraufruf natuerlich mit der Optimierungsoption -Os). Ansonsten 
scheint der avrgcc 3.3 uebrigens besser zu optimieren als der avrgcc 
3.02

Ich habe allerdings bisher nur Code fuer den AT2313 und AT2343/23 
produziert. Kann sein, dass der Optimizer fuer den MEGA128 anders 
agiert...

MfG,
- Michael Bergmann

von nolife (Gast)


Lesenswert?

Ich kenne AVREdit, hab es kurz ausprobiert war für etwa 5 Sekunden 
begeistert dann bereits enttäuscht.
Ich kann die störenden Punkte und Bugs zwar nicht näher benennen aber es 
gab davon reichlich.

Ich verwende derzeit Ultraedit mit 3 kurzbefehlen,
compile,clean,upload.
Damit kann man sehr angenehm arbeiten da Ultraedit an sich ein sehr 
ausgearbeiteter Editor ist (man kann blöcke markieren und mit tab 
gemeinsam ausrücken, er kann c++ und asm code farblich hervorheben wie 
ein normales gui, und die Handhabenung mit Dateien in einem Projekt etc. 
ist sehr angenehm, dazu kanne r auch in die Errorzeile Springen und die 
compilerwarnungen und errors in nem dockingfenster anzeigen)
Es ist leider Shareware, also entweder crack oder kaufen wenn mans damit 
machen will.

Meiner Meinung nach ist die GUI des MS VC++ die Beste, sehr angenehm 
handhabbar, exakt auf den Zweck angepasst, und ich finde es angenehm 
wenn man zb strcpy( schreibt das prorgamm klein einblendet welche 
Befehle es gibt) oder man auf die selbe art irgendeinestrcutvariable. 
schreibt (und alle members gelistet werden).

Der größte Nachteil von AVRgcc ist wie schon gesagt die Handhabung, wenn 
zb ein Entwickler zum ersten mal auf einem atmel entwickeln möchte und 
er vor der Compilerwahl steht ist es unwarscheinlich dass avrgcc 
genommen wird.
Ich gehe davon aus dass er unter windows entwickeln möchte, dann
steht er vor dem Problem dass er nicht ienmal ein von Anfang an 
funktionsfähiges Release bekommt, bzw die veraltete .2 Version 
downloaden muss (und auch da muss man readmes etc lesen usw.)
Man nehme ICC und hat alles sofort lauffähig, einen click auf setup.exe 
und das Ding hat eine brauchbare gui und alles weitere integriert, 
compilersettings sieht man erklärt und checkboxes, F1
bringt eine Hilfe zum Compiler und kennt den Syntax.
inline asm ist weitaus angenehmer als der von gcc.
und makefiles gibts gar keine mehr, man muss keine Abhängigkeiten etc 
definieren.

Ist natürlich fraglich ob es sowas jemals für den avrgcc geben wird da 
das Tool für Unix entwickelt wird.

von BAB (Gast)


Lesenswert?

eine richtige ide wirds wohl eher nicht geben...aber eric weddington 
arbeitet gerade am januar release für winavr3.4..dort soll ein 
eigenständiger editor mit dabei sein der einige sachen vereinfachen 
soll...

von Joerg Wunsch (Gast)


Lesenswert?

Die Geschichte mit dem bit_is_clear() war eindeutig ein Denkfehler
von Marek.  Der C-Standard verlangt halt, daß die Argumente für den
Tilde-Operator erst zu promoten sind (zu "int" in diesem Falle),
bevor der Operator angewandt wird.

Mittlerweile hat jemand einen offiziellen Bugreport geschrieben und
dort eine effektivere Version angeboten: !bit_is_set() tut's
nämlich ohne diesen Seiteneffekt.

Das wird in der nächsten WinAVR dabei sein, da es schon im CVS ist,
Eric aber den Sourcecode für die neue Version noch nicht gezogen
hat.

scanf() wird übrigens auch dabei sein...

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.