mikrocontroller.net

Forum: Compiler & IDEs GCC Optimierung?


Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hier habe ich eine einfache Routine, welche ich mit der Option -O3 
compiliere.
Mir geht es dabei in erster Linie darum, was der Compilter mit dem 
Inhalt der while-Schleife anstellt.
  unsigned char *readptr = UART0.RxReadPtr;
  unsigned char size = (*readptr)+1;
  if (MQReserve(size)) {
    while(size--) {
        MQAdd8(*readptr++);
    }
    UART0.RxReadPtr=readptr;
  }

Der Disassembler Code hierzu lautet
+00000195:   930F        PUSH    R16              Push register on stack
+00000196:   931F        PUSH    R17              Push register on stack
+00000197:   93CF        PUSH    R28              Push register on stack
+00000198:   93DF        PUSH    R29              Push register on stack
59:         unsigned char *readptr = UART0.RxReadPtr;
+00000199:   91C00000    LDS     R28,0x0000       Load direct from data space
+0000019B:   91D001CD    LDS     R29,0x01CD       Load direct from data space
60:         unsigned char size = (*readptr)+1;  // add one for message lenght byte  UNLOCK_IRQ
+0000019D:   8108        LDD     R16,Y+0          Load indirect with displacement
+0000019E:   2F10        MOV     R17,R16          Copy register
+0000019F:   5F1F        SUBI    R17,0xFF         Subtract immediate
61:         if (MQReserve(size)) {
+000001A0:   2F81        MOV     R24,R17          Copy register
+000001A1:   940E01C5    CALL    0x000001C5       Call subroutine
+000001A3:   2388        TST     R24              Test for Zero or Minus
+000001A4:   F0D9        BREQ    PC+0x1C          Branch if equal
62:           while(size--) {
+000001A5:   2311        TST     R17              Test for Zero or Minus
+000001A6:   F0A9        BREQ    PC+0x16          Branch if equal
+000001A7:   01DE        MOVW    R26,R28          Copy register pair
+000001A8:   2F20        MOV     R18,R16          Copy register
+000001A9:   E030        LDI     R19,0x00         Load immediate
+000001AA:   5F2F        SUBI    R18,0xFF         Subtract immediate
+000001AB:   4F3F        SBCI    R19,0xFF         Subtract immediate with carry
+000001AC:   0F2C        ADD     R18,R28          Add without carry
+000001AD:   1F3D        ADC     R19,R29          Add with carry
+000001AE:   91E00472    LDS     R30,0x0472       Load direct from data space
+000001B0:   91F00473    LDS     R31,0x0473       Load direct from data space
63:               MQAdd8(*readptr++);
+000001B2:   918D        LD      R24,X+           Load indirect and postincrement
+000001B3:   9381        ST      Z+,R24           Store indirect and postincrement
+000001B4:   93F00473    STS     0x0473,R31       Store direct to data space
+000001B6:   93E00472    STS     0x0472,R30       Store direct to data space
+000001B8:   17A2        CP      R26,R18          Compare
+000001B9:   07B3        CPC     R27,R19          Compare with carry
+000001BA:   F7B9        BRNE    PC-0x08          Branch if not equal
+000001BB:   01ED        MOVW    R28,R26          Copy register pair
65:           UART0.RxReadPtr=readptr;
+000001BC:   93D001CD    STS     0x01CD,R29       Store direct to data space
+000001BE:   93C001CC    STS     0x01CC,R28       Store direct to data space
67:       }
+000001C0:   91DF        POP     R29              Pop register from stack
+000001C1:   91CF        POP     R28              Pop register from stack
+000001C2:   911F        POP     R17              Pop register from stack
+000001C3:   910F        POP     R16              Pop register from stack
+000001C4:   9508        RET                      Subroutine return

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ups, da fehlt noch was.

Seht Euch mal den Inhalt der whileschleife an. R17 hält die Variable 
"size".
Aber anstatt die size (R17) zu decrementieren, wird ein unnützer 2 Byte 
großer Addresspointer mit einem Zielwert verglichen. Dadurch werden 3 
Befehler mehr benötigt, als R17 zu decrementieren.

Grüße,
Dirk

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Übrigens, der Schleifeninhalt liegt zwischen 0x1B2 und 0x1BA.

Autor: Klaus (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du hast doch selber schon bemerkt, dass du ohne optimierung kompilierst!

Mach die Optimierung an, dann verschwinden auch die überflüssigen 
Befehle.

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

Bewertung
0 lesenswert
nicht lesenswert
Kannst du das mal irgendwie lesbar darstellen?  Die Markierung für
C-Code heißt nicht code sondern c, wenn du schon unbedingt
Disassembler posten möchtest, dann mit pre markieren.  Die völlig
unnützen Kommentare des AVR-Studio-Disassemblers kannst du aber
eigentlich auch gleich entfernen: wer nicht weiß, dass BRNE ein
"branch if not equal" ist, dem wird der Kommentar auch kaum zum
Verständnis helfen...

Besser wäre es eigentlich, wenn du dein Beispiel soweit minimal
runterbrechen kannst, dass man es selbst compilieren kann.  Mir
ist persönlich die Assembler-Ausgabe des Compilers deutlich lieber
zu lesen als all der Disassembler-Kram, egal ob es der vom GNU
Disassembler ist (das typische .lst-File) oder vom AVR Studio.

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

Bewertung
0 lesenswert
nicht lesenswert
Hi,

hier ein kleines (sinnloses) Beispielprogramm. Die Schliefe wird genauso 
compiliert, wie in meinem Beispiel.

Grüße,
Dirk

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Viele Optimierungen von GCC gehen wie die Sprache C selbst davon aus, 
dass die Wortbreite der zugrunde liegenden Maschine für "int" und für 
Pointer ausreicht. AVR ist die m.W. einzige Architektur mit offizieller 
GCC Portierung auf die das nicht zutrifft.

Hier zeigt sich das exemplarisch. Der Compiler geht im Rahmen der 
maschinenunabhängigen Optimierung davon aus, dass Operationen mit dem 
Pointer nicht teurer sind als Operationen mit dem Zähler. Dass diese 
Annahme bei AVR falsch ist, das ist Pech.

Man kann auch sonst nicht vom Compiler erwarten, dass er jeden 
Codewunsch optimal erfüllt. Insgesamt ist der obige Code garnicht übel 
geraten. Wenn du höhere Ansprüche hast, dann ist ein Compiler, dessen 
Optimierungsstrategien insbesondere der 4er Versionen eher auf 
High-Performance-Maschinen abziehlen, möglicherweise die falsche Wahl. 
Aber probier die Alternativen lieber erst aus, ob die wirklich besser 
sind.

Autor: Dieter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Klaus: Da steht -O3 und nicht O0...

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Was mich an dem Code übrigens eher stört, ist die fehlende 
Registeroptimierung eines der beiden Pointer. Allerdings stecke ich 
nicht tief genug im Registermodell vom avr-gcc drin. Sieht so aus, als 
ob er nicht die Freiheit hat, das Z-Register entsprechend belegen zu 
dürfen.

Ansonsten ist die Schleife unter der Annahme einer wortverarbeitenden 
Maschine optimal umgesetzt.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich dacht an ein
loop:
...
SUBI R17, 0x01           ; R17 ist mein Zähler
BRNE loop
anstatt
LD      R24,X+           
+ST     Z+,R24
STS     0x0473,R31       ; hier wird der pointer extra geholt
STS     0x0472,R30
CP      R26,R18          ; um ihn dann als 16 Bit Zahl zu vergleichen
CPC     R27,R19
BRNE    PC-0x08

Mal abgesehen von der Optimierung für 16 Bit Rechner. Das dekrementieren 
eines Zähler mittels "subtract" ist auch auf 16-Bit Rechnern nur ein 
Befehl. Der Vergleich kann in diesem Fall entfallen, da ja das Zero-Flag 
diese Aufgabe automatisch bei
while (size--)
 übernimmt.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Optimal im Sinn von GCC umgesetzt wäre
  LD      R24,X+
  ST      Z+,R24
  CPW     R26,R18    (wenn es den Befehl gäbe)
  BRNE    PC-0x08
was sich der Anzahl Befehle nach nicht von
  LD      R24,X+
  ST      Z+,R24
  DEC     R17
  BRNE    PC-0x08
unterscheidet.

Dass CPW einen Befehl länger und eine Takt langsamer ist, das ist der 
fehlenden Wortverarbeitung zuzurechnen.

STS läd übrigens nicht, sondern speichert.

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

Bewertung
0 lesenswert
nicht lesenswert
Ja, der GCC 4.3 hat ein AVR-Dilemma.  Das liegt vor allem daran, dass
die GCC-Entwickler keine Möglichkeit haben, ihre neuen Entwicklungen
überhaupt daraufhin zu testen, ob diese auf einem AVR u. U. eine
nennenswerte Verschlechterung darstellen.  Sie merken das dann erst
über Bugreports.

Was dich stört, ist ja offenbar:
.L4:
.LM6:
        ld r24,X+
        st Z+,r24
        sts (WritePtr)+1,r31
        sts WritePtr,r30
.LM7:
        cp r26,r18
        cpc r27,r19
        brne .L4

GCC 4.2.2 hat das noch besser gekonnt:
.L5:
.LM7:
        ld r24,X+
        st Z+,r24
        sts (WritePtr)+1,r31
        sts WritePtr,r30
.LM8:
        subi r25,1
        brcc .L5

Du kannst ihm aber auch durch cachen von WritePtr in einer lokalen
Variablen helfen (wie du es ja für RxReadPtr auch schon machst).
Dann sieht der generierte Code so aus:

GCC 4.3.1
.L4:
.LM4:
        ld r24,X+
        st Z+,r24
.LM5:
        cp r30,r18
        cpc r31,r19
        brne .L4

GCC 4.2.2:
.L5:
.LM5:
        ld r24,Z+
        st X+,r24
.LM6:
        subi r25,1
        brcc .L5

OK, GCC 4.2 ist immer noch 12,5 % schneller als GCC 4.3.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Da habe ich wohl nicht richtig gelesen (peinlich).

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, kann er Z also doch belegen. Hätte eigentlich gedacht, dass er das 
selber hinkriegen könnte, da aufgrund verschiedener Datentypen und 
-grössen kein Risiko von Aliasing besteht. Oder ist er standardmässig 
auf "paranoid" eingestellt?

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

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Ja, der GCC 4.3 hat ein AVR-Dilemma.  Das liegt vor allem daran, dass
> die GCC-Entwickler keine Möglichkeit haben, ihre neuen Entwicklungen
> überhaupt daraufhin zu testen, ob diese auf einem AVR u. U. eine
> nennenswerte Verschlechterung darstellen.  Sie merken das dann erst
> über Bugreports.

Ob sich dieser inzwischen nicht ganz unerhebliche Missstand wohl wieder 
bessert? Weiß jemand, ob daran gearbeitet wird, dass der GCC die 
"kleinen" CPUs besser unterstützt in Zukunft bzw. besteht überhaupt noch 
ein Interesse seitens der GCC-Entwickler die 8-Bit CPUs noch sinnvoll zu 
unterstützen? So langsam ist es schon bitter was da kommt. Ich meine 
gut, GCC kostet nichts und der Compiler ist leistungsfähig, aber was da 
an Codegröße erzeugt wird, da kann man nur mit gutem Willen von 
Optimierung sprechen.

Hat jemand das Wissen, wo es hingehen soll mit dem GCC?

Und wiese können Sie das nicht testen? Wie wird es denn mit anderen CPUs 
getestet? Ich hab da leider keinen Einblick.

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

Bewertung
0 lesenswert
nicht lesenswert
Es gibt ,,die GCC-Entwickler'' nicht, die sich darum kümmern könnten.
Es gibt zwei oder drei Entwickler, die sich um den AVR-GCC kümmern,
und die hatten in letzter Zeit alle Hände voll zu tun, den Xmega
einzubinden, da bei dem doch einiges anders ist als bei den vorigen
AVRs.

,,Die GCC-Entwickler'' brauchen insbesondere einen passenden Simulator,
mit dem man eine Testumgebung für den AVR-GCC so aufbauen kann, dass
sie bei Veränderungen am Compiler ermitteln können, ob der AVR-Code
dadurch schlechter wird.  Mit einer solchen Umgebung hätte der AVR-Port
die Chance, aus der Kategorier ,,ferner liefen'' in der Wahrnehmung im
GCC in die zweite Stufe aufzusteigen.  Dann wäre eine Verschlechterung
des AVR-Codes bei grundsätzlichen Änderungen automatisch erkennbar und
würde erst einmal zu einer Art Ausrufezeichen führen: ,,das, was jetzt
gerade passiert, ergibt für wenigstens ein "tier 2 target" eine
Regression''.

Bislang, also als "tier 3" geht sowas nur nach dem Release über
Bugreports.  Dann ist die grundsätzliche Änderung aber schon drin,
und man kann ihr nur noch hinterherlaufen.

Es gibt übrigens durchaus Codebeispiele, bei denen der GCC 4.3 besseren
Code auch für den AVR liefert als seine Vorgänger, ist also nicht so,
dass neue Optimierungen prinzipiell Mist sind.  Aber die treibenden
Kräfte in der GCC-Entwicklung sind (dank der Masse) natürlich auf
i386 und x86_64 konzentriert und dort in vielen Fällen wieder auf die
Dinge, die die Welt derzeit am meisten benutzt, also neben C auch noch
C++.

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

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Es gibt ,,die GCC-Entwickler'' nicht, die sich darum kümmern könnten.
> Es gibt zwei oder drei Entwickler, die sich um den AVR-GCC kümmern,

Das sind dann doch "die GCC Entwickler" für den AVR. Die meinte ich 
jedenfalls :-)

> und die hatten in letzter Zeit alle Hände voll zu tun, den Xmega
> einzubinden, da bei dem doch einiges anders ist als bei den vorigen
> AVRs.

Jetzt sind die Xmegas doch drin. D.h. es kann besser werden.

> ,,Die GCC-Entwickler'' brauchen insbesondere einen passenden Simulator,
> mit dem man eine Testumgebung für den AVR-GCC so aufbauen kann, dass

Hmmm... verstanden.

> Bislang, also als "tier 3" geht sowas nur nach dem Release über
> Bugreports.  Dann ist die grundsätzliche Änderung aber schon drin,
> und man kann ihr nur noch hinterherlaufen.

Das ist ja wenigstens ein winziger Trost, dass es grundsätzlich nicht so 
bleiben soll.

> Es gibt übrigens durchaus Codebeispiele, bei denen der GCC 4.3 besseren
> Code auch für den AVR liefert als seine Vorgänger, ist also nicht so,
> dass neue Optimierungen prinzipiell Mist sind.

Ja das habe ich auch nicht so gemeint. Aber "unterm Strich" ist es 
zumindest bei meinen Versuchen längerer Code geworden. Ich habe ein paar 
von meinen Projekten mit unterschiedlichen GCC Versionen kompilert und 
auchdie hier im Forum vorgeschlagenen Optimierungen probiert und "unterm 
Strich" war der Code länger. Also es mag sicher Optimierungen geben, die 
bei den neuen Compilern besser sind aber "unterm Strich" über ein 
Projekt gesehen war es bei mir zumindest lägerer Codeder erzeugt wurde.

> Aber die treibenden
> Kräfte in der GCC-Entwicklung sind (dank der Masse) natürlich auf
> i386 und x86_64 konzentriert und dort in vielen Fällen wieder auf die
> Dinge, die die Welt derzeit am meisten benutzt, also neben C auch noch
> C++.

Da ATMEL ja auch unter anderem auf den GCC setzt, sind sie meiner 
Meinung nach ein wenig "in der Pflicht", auch mit zu arbeiten. Sprich 
mehr als nur 3 Leute an dem AVR-GCC arbeiten zu lassen. GCC ist zwar 
Open-Source, aber auch ATMEL wird damit seinen Umsatz ankurbeln. Aber 
wahrscheinlich kommen die 3 Leute schon von ATMEL :-)

Das wiederum bedeutet, bei ATMEL gibt es ein paar freie Arbeitsplatze 
für Softwareentwickler ;-) Also bewerbt Euch dort :-)

Nun, ich will/wollte den GCC ganz bestimmt nicht schlecht machen (habe 
auch an anderen Stellen hier im Forum den GCC immer eher gelobt). Mich 
hat eher interessiert, wie es zu diesem Umstand kommen kann und warum es 
nicht besser wird im Moment.

Aber diese Optimierungsgeschichten verdienen den Namen im Moment nur zum 
Teil. Ich finde dieser Punkt ist imzwischen schon mehr als eine kleine 
Schwäche. Nun, hoffen wir, dass das irgendwann wieder besser wird oder 
eher dass es irgendwann eine passende Testumgebung zum testen geben 
wird.

Ja ja, ich könnte da auch mithelfen. Es steht auch mir frei ;-)

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Die Optimierung -O3 ist auf Geschwindigkeit ausgelegt. Wenn Du allein 
die Code-Länge vergleichst, nim -Os.

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

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:
> Die Optimierung -O3 ist auf Geschwindigkeit ausgelegt. Wenn Du allein
> die Code-Länge vergleichst, nim -Os.

Danke für den Tip, aber dass war mir bekannt. Diese Option  (-Os) 
benutze ich auch fast ausschließlich. Damit habe ich auch getestet.

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

Bewertung
0 lesenswert
nicht lesenswert
Ich war mal neugierig, was z.B. der CodeVision-Compiler von der Schleife 
macht. Der ist ja vom Preis noch eher im "Bastlerbereich" :-)
Habe mir die aktuelle Eval-Version installiert und zweimal den Compiler 
laufen lassen.
1. Optimierung SPEED (1. Auszug im Listing unten)
2. Optimierung SIZE  (2. Auszug im Listing unten)

Beides mal der gleiche Code. Ich war so verdutzt, dass ich es nochmal 
probiert habe. Und wieder das Ergebnis. Und es sieht immer noch deutlich 
schlechter aus, als der "schlechte" Code des GCC.

Es sei denn, in der Eval-Version funktioniert die Optimierung nicht.
Ich habe aber auf der Homepage wie auch in dem Manual keinen Hinweis auf 
diese Limitierung gefunden. Es war nur die Limitierung der generierten 
Codegröße erwähnt.

Also da kann ich ja trotz dieses Dilemmas im GCC weiter ruhig schlafen 
;-)

[Edit:]
Man müßte allerdings mal ein ganzes Projekt vergleichen. So hinkt der 
Vergleich ja eigentlich.

;Optimierung SPEED
;    0000 0015     while(size--) {
                 _0x4:
000074 2fe3        MOV  R30,R19
000075 5031        SUBI R19,1
000076 30e0        CPI  R30,0
000077 f061        BREQ _0x6
;    0000 0016         *WritePtr++=*readptr++;
000078 01f3        MOVW R30,R6
000079 9631        ADIW R30,1
00007a 013f        MOVW R6,R30
00007b 9731        SBIW R30,1
00007c 010f        MOVW R0,R30
00007d 01d8        MOVW R26,R16
                +
00007e 5f0f     +SUBI R16 , LOW ( - 1 )
00007f 4f1f     +SBCI R17 , HIGH ( - 1 )
                   __ADDWRN 16,17,1
000080 91ec        LD   R30,X
000081 01d0        MOVW R26,R0
000082 93ec        ST   X,R30
;    0000 0017   }
000083 cff0        RJMP _0x4
                 _0x6:


;Optimierung SIZE
;    0000 0015     while(size--) {
                 _0x4:
000074 2fe3        MOV  R30,R19
000075 5031        SUBI R19,1
000076 30e0        CPI  R30,0
000077 f061        BREQ _0x6
;    0000 0016         *WritePtr++=*readptr++;
000078 01f3        MOVW R30,R6
000079 9631        ADIW R30,1
00007a 013f        MOVW R6,R30
00007b 9731        SBIW R30,1
00007c 010f        MOVW R0,R30
00007d 01d8        MOVW R26,R16
                +
00007e 5f0f     +SUBI R16 , LOW ( - 1 )
00007f 4f1f     +SBCI R17 , HIGH ( - 1 )
                   __ADDWRN 16,17,1
000080 91ec        LD   R30,X
000081 01d0        MOVW R26,R0
000082 93ec        ST   X,R30
;   0000 0017   }
000083 cff0        RJMP _0x4
                 _0x6:



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

Bewertung
0 lesenswert
nicht lesenswert
Oh je! Alles zurück. Ich habe eben erst bemerkt, dass der Codeauszug im 
Posting von Jörg oben nur ein Auszug der Schleife ist. Sollte wohl doch 
noch erst ein "Hallo Wach" nehmen. Also bei dem Vergleich der Codegröße 
der gesamten Schleife ist der GCC doch schlechter. Bei GCC mit -Os aber 
allerdings nicht. Sorry für die Verwirrung.

Hier der Auszug vom GCC über die gesamte Schleife
; Optimierung -O3
    while(size--) {
  b4:  2f 3f         cpi  r18, 0xFF  ; 255
  b6:  a1 f0         breq  .+40       ; 0xe0 <main+0x4e>
  b8:  df 01         movw  r26, r30
  ba:  30 e0         ldi  r19, 0x00  ; 0
  bc:  2f 5f         subi  r18, 0xFF  ; 255
  be:  3f 4f         sbci  r19, 0xFF  ; 255
  c0:  2e 0f         add  r18, r30
  c2:  3f 1f         adc  r19, r31
  c4:  e0 91 66 00   lds  r30, 0x0066
  c8:  f0 91 67 00   lds  r31, 0x0067
        *WritePtr++=*readptr++;
  cc:  8d 91         ld  r24, X+
  ce:  81 93         st  Z+, r24
  d0:  f0 93 67 00   sts  0x0067, r31
  d4:  e0 93 66 00   sts  0x0066, r30

    RxReadPtr=data;
    WritePtr = target;

    while(size--) {
  d8:  a2 17         cp  r26, r18
  da:  b3 07         cpc  r27, r19
  dc:  b9 f7         brne  .-18       ; 0xcc <main+0x3a>
  de:  fd 01         movw  r30, r26
        *WritePtr++=*readptr++;
  }

; Optimierung -Os
  be:  0b c0         rjmp  .+22       ; 0xd6 <main+0x44>

    while(size--) {
        *WritePtr++=*readptr++;
  c0:  89 91         ld  r24, Y+
  c2:  e0 91 66 00   lds  r30, 0x0066
  c6:  f0 91 67 00   lds  r31, 0x0067
  ca:  81 93         st  Z+, r24
  cc:  f0 93 67 00   sts  0x0067, r31
  d0:  e0 93 66 00   sts  0x0066, r30
  d4:  91 50         subi  r25, 0x01  ; 1

    RxReadPtr=data;
    WritePtr = target;


    while(size--) {
  d6:  99 23         and  r25, r25
  d8:  99 f7         brne  .-26       ; 0xc0 <main+0x2e>
        *WritePtr++=*readptr++;
  }



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

Bewertung
0 lesenswert
nicht lesenswert
900ss D. wrote:

> Da ATMEL ja auch unter anderem auf den GCC setzt, sind sie meiner
> Meinung nach ein wenig "in der Pflicht", auch mit zu arbeiten.

Kennst du jemanden, der GCC intern genug versteht und sich von Atmel
in Trondheim anheuern lassen würde? :-)

GCC ist leider in seinen Interna nicht gerade leicht zu verstehen,
was die natürliche Auslese etwas beschränkt.

Wichtiger wäre ja wohl fast noch ein vernünftiger Opensource-Simulator,
damit die GCC-Entwickler etwas in der Hand haben, das sie zum Testen
benutzen können.  Da sieht's bald noch dünner aus als mit Leuten, die
AVR-GCC verstehen.

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

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:
> Kennst du jemanden, der GCC intern genug versteht und sich von Atmel
> in Trondheim anheuern lassen würde? :-)

Nee, kenne ich nicht und ich selber bin auch absolut kein 
"Compilerbauer" und hab grad 'n neuen Job. Da ist es noch ganz gut. Aber 
ich hab einen Kollegen dort (Softwareentwickler), der mag Norwegen sehr 
gern und macht dort jedes Jahr Urlaub :-) Er spricht sogar die Sprache.

> Wichtiger wäre ja wohl fast noch ein vernünftiger Opensource-Simulator,
> damit die GCC-Entwickler etwas in der Hand haben, das sie zum Testen
> benutzen können.

Das sehe ich auch so. Dann müßten die Entwickler nicht auf Bug-Reports 
warten. Es müßten automatische Tests laufen können, am besten noch mit 
einer automatischen Analyse hinterher. träum....

Autor: schmocka (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Kennst du jemanden, der GCC intern genug versteht und sich von Atmel
> in Trondheim anheuern lassen würde? :-)
Wieso Trondheim? Ist das ein Insider, dank der Internets/Mail dürfte der
Ort unwichtig sein?

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Das Middleend (4.3.2 mit -Os) macht aus dem Code folgendes:
;; Function foo (foo)

foo ()
{
  unsigned char size;
  unsigned char * readptr;
  unsigned char * WritePtr.0;

<bb 2>:
  RxReadPtr = &data;
  WritePtr = &target;
  size = data[0] + 1;
  readptr = &data;
  goto <bb 4>;

<bb 3>:
  WritePtr.0 = WritePtr;
  *WritePtr.0 = MEM[base: readptr];
  WritePtr = WritePtr.0 + 1;
  readptr = readptr + 1;

<bb 4>:
  if (readptr != (unsigned char *) (unsigned int) (&data + (unsigned int) size))
    goto <bb 3>;
  else
    goto <bb 5>;

<bb 5>:
  RxReadPtr = readptr;
  return;

}

1) Die Schleifenvariable 'size' ist eliminiert. Prinzipiell mal gut, 
weil das Register spart

2) WritePtr wird nicht aus der Schleife gezogen. Erstens weiß ich net, 
ob GCC das schon optimieren könnte (das am SSA zu erkennen ist kein 
Akt), allerdinge geht es nicht wegen möglichem Aliasing: *WritePrt.0=... 
könnte WritePrt verändern.

Das .o ist 80 Byte groß. Den Code habe ich in eine eigene Funktion 
gefasst.
avr-gcc 3.4.6 macht mit -Os übrigens einen Code, der um die erwarteten 
10% kleiner ist: 72 Bytes. Dort wird die Schleifenvariable nicht 
eliminiert.

Evtl kann man die "Optimierung" verhindern, aber das ist dann ein Schlag 
mit der Keule auf's ganze Projekt/Modul.

Um zu sehen, welche Teiloptionen zB -O3 mit sich bringt, einfach mit 
-fverbose-asm übersetzen und in der cc1-Ausgabe (*.s) stehen die 
Optionen, für die man nacheinander Deaktivierung versuchen kann.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. wrote:

> Akt), allerdinge geht es nicht wegen möglichem Aliasing: *WritePrt.0=...
> könnte WritePrt verändern.

Hatte ich zunächst ja auch vermutet, aber laut GCC Doku ist ab -O2/-Os 
die Option -fstrict-aliasing aktiv, in der Aliasing nur bei gleichen 
oder ähnlichen Daten (wie int<=>unsigned) berücksichtigt werden muss. 
Was hier nicht zutrifft. Seitens der Sprachdefinition wäre es 
ausreichend, den Pointer hinter der Schleife zu aktualisieren.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. wrote:

> 1) Die Schleifenvariable 'size' ist eliminiert. Prinzipiell mal gut,
> weil das Register spart

Nö. Da nun die Enderkennung über die Endadresse erfolgt, wird alternativ 
dafür ein Register verbraten.

Autor: Stefan B. (stefan) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Jörg Wunsch wrote:

> Ja, der GCC 4.3 hat ein AVR-Dilemma.  Das liegt vor allem daran, dass
> die GCC-Entwickler keine Möglichkeit haben, ihre neuen Entwicklungen
> überhaupt daraufhin zu testen, ob diese auf einem AVR u. U. eine
> nennenswerte Verschlechterung darstellen.  Sie merken das dann erst
> über Bugreports.

Was sind denn die Maßzahlen, an denen eine solche 
Verschlechterung/Verbesserung festgemacht wird?

Die Codegrösse ist ohne Tester ersichtlich.

Zum Abschätzen des Stackbedarfs könnte das neue Tool von Benedikt (=> 
Codesammlung) beitragen

Für die Ausführungszeit bräuchte man einen Simulator, wobei die Frage 
ist, was similiert werden muss bzw. wie die Testsuite aussieht. Muss der 
komplette Prozessor inkl. IO und Schnittstellen oder "nur" die 
Grundfunktionen simuliert/emuliert werden?

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

Bewertung
0 lesenswert
nicht lesenswert
Stefan B. wrote:

> Was sind denn die Maßzahlen, an denen eine solche
> Verschlechterung/Verbesserung festgemacht wird?
>
> Die Codegrösse ist ohne Tester ersichtlich.

Das Problem ist, dass du bei GCC einfach nicht in der "tier 2"-
Kategorie landest, wenn der generierte Code nicht durch alle
GCC-Entwickler auch simuliert werden kann.

IOs müssen sicher nicht simuliert werden bzw. nur in begrenztem
Maße (ich könnte mir ein Rücklesen von Portregistern vorstellen).
Welche Anforderungen genau nötig sind, müsste ich auch nachlesen.

Autor: Shagoon (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
gcc 4.3.2 erzeugt mit
avr-gcc -S Optimizer.c -O3
.L5:
        ld r24,X+
        st Z+,r24
        sts (WritePtr)+1,r31
        sts WritePtr,r30
        subi r25,1
        brcc .L5

mit
avr-gcc -S Optimizer.c -O3 -ffreestanding -fwhole-program
 wird jedoch die optimiale Version
.L5:
        ld r24,X+        ;  tmp53,
        st Z+,r24        ; , tmp53
        subi r18,1       ;  size.38
        brcc .L5         ; 
 erzeugt.

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

Bewertung
0 lesenswert
nicht lesenswert
-ffreestanding ist zwiespältig.  Die avr-libc bietet doch eine recht
nette Untermenge der Standardbibliothek, und mit -fhosted (default)
kann der Compiler Optimierungen auf Basis des internen Wissens über
die Bibliothek vornehmen.  Diese Möglichkeit vergibt man sich mit
-ffreestanding.  Ein Beispiel wäre strlen("Hello, world!\n"), das
wäre mit -fhosted die Konstante 14, mit -ffreestanding dagegen ein
zur Laufzeit vorzunehmender Funktionsaufruf.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
A. K. wrote:
> Johann L. wrote:
>
>> Akt), allerdinge geht es nicht wegen möglichem Aliasing: *WritePrt.0=...
>> könnte WritePrt verändern.
>
> Hatte ich zunächst ja auch vermutet, aber laut GCC Doku ist ab -O2/-Os
> die Option -fstrict-aliasing aktiv, in der Aliasing nur bei gleichen
> oder ähnlichen Daten (wie int<=>unsigned) berücksichtigt werden muss.
> Was hier nicht zutrifft. Seitens der Sprachdefinition wäre es
> ausreichend, den Pointer hinter der Schleife zu aktualisieren.

Ein char* kann doch alias für alles sein? Bin nicht sooo tief in der 
Spez ;-)


>> 1) Die Schleifenvariable 'size' ist eliminiert. Prinzipiell mal gut,
>> weil das Register spart

> Nö. Da nun die Enderkennung über die Endadresse erfolgt, wird alternativ
> dafür ein Register verbraten.

Stimmt, Register spart's keine weil size in BB4 noch rechts von != 
auftaucht. Allerdings werden Operationen gespart, weil der Vergleich in 
BB4  ne Schleifeininvariante geworden ist. Das alles wie gesagt aus der 
Sicht des Middleend.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Johann L. wrote:

> Ein char* kann doch alias für alles sein? Bin nicht sooo tief in der
> Spez ;-)

Grad mal in C99 reingesehen. Hast wohl recht, für "char" gelten offenbar 
Sonderregeln.

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wofor ist den -fwhole-program dar? Ich konnte in der WinAVR 
Dokumentation nichts finden.

Allerdings verhindert dieser Compilerschalter, daß ich mein Programm 
kompilieren kann. Plötzlich sind irgendwelche Funktionen oder Variablen 
nicht mehr bekannt.

Autor: Johann L. (gjlayde) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:
> Wofor ist den -fwhole-program dar? Ich konnte in der WinAVR
> Dokumentation nichts finden.

Hast du beim gcc-Aufruf auch alle Quellen angegeben?
Sonst landet unbenutztes Zeug gnadenlos in der Tonne, auch wenn's extern 
ist.

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dirk wrote:

> Wofor ist den -fwhole-program dar? Ich konnte in der WinAVR
> Dokumentation nichts finden.

http://gcc.gnu.org/onlinedocs/gcc-4.3.2/gcc/Optimi...

Autor: Dirk (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> Hast du beim gcc-Aufruf auch alle Quellen angegeben?
> Sonst landet unbenutztes Zeug gnadenlos in der Tonne, auch wenn's extern
> ist.
Macht das AVR Studio das nicht automatisch?

Autor: A. K. (prx)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Nein. In diesem Fall müssen ziemlich sicher alle zusammen in einem 
Aufruf angegeben werden. Nicht wie sonst einzeln.

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.