Forum: Compiler & IDEs GCC Optimierung?


von Dirk (Gast)


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.
1
  unsigned char *readptr = UART0.RxReadPtr;
2
  unsigned char size = (*readptr)+1;
3
  if (MQReserve(size)) {
4
    while(size--) {
5
        MQAdd8(*readptr++);
6
    }
7
    UART0.RxReadPtr=readptr;
8
  }

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

von Dirk (Gast)


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

von Dirk (Gast)


Lesenswert?

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

von Klaus (Gast)


Lesenswert?

Du hast doch selber schon bemerkt, dass du ohne optimierung kompilierst!

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

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


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.

von Dirk (Gast)


Angehängte Dateien:

Lesenswert?

Hi,

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

Grüße,
Dirk

von (prx) A. K. (prx)


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.

von Dieter (Gast)


Lesenswert?

@Klaus: Da steht -O3 und nicht O0...

von (prx) A. K. (prx)


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.

von Dirk (Gast)


Lesenswert?

Ich dacht an ein
1
loop:
2
...
3
SUBI R17, 0x01           ; R17 ist mein Zähler
4
BRNE loop
anstatt
1
LD      R24,X+           
2
+ST     Z+,R24
3
STS     0x0473,R31       ; hier wird der pointer extra geholt
4
STS     0x0472,R30
5
CP      R26,R18          ; um ihn dann als 16 Bit Zahl zu vergleichen
6
CPC     R27,R19
7
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
1
while (size--)
 übernimmt.

von (prx) A. K. (prx)


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.

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


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:
1
.L4:
2
.LM6:
3
        ld r24,X+
4
        st Z+,r24
5
        sts (WritePtr)+1,r31
6
        sts WritePtr,r30
7
.LM7:
8
        cp r26,r18
9
        cpc r27,r19
10
        brne .L4

GCC 4.2.2 hat das noch besser gekonnt:
1
.L5:
2
.LM7:
3
        ld r24,X+
4
        st Z+,r24
5
        sts (WritePtr)+1,r31
6
        sts WritePtr,r30
7
.LM8:
8
        subi r25,1
9
        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
1
.L4:
2
.LM4:
3
        ld r24,X+
4
        st Z+,r24
5
.LM5:
6
        cp r30,r18
7
        cpc r31,r19
8
        brne .L4

GCC 4.2.2:
1
.L5:
2
.LM5:
3
        ld r24,Z+
4
        st X+,r24
5
.LM6:
6
        subi r25,1
7
        brcc .L5

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

von Dirk (Gast)


Lesenswert?

Da habe ich wohl nicht richtig gelesen (peinlich).

von (prx) A. K. (prx)


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?

von 900ss (900ss)


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.

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


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++.

von 900ss (900ss)


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

von Dirk (Gast)


Lesenswert?

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

von 900ss (900ss)


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.

von 900ss (900ss)


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.
1
;Optimierung SPEED
2
;    0000 0015     while(size--) {
3
                 _0x4:
4
000074 2fe3        MOV  R30,R19
5
000075 5031        SUBI R19,1
6
000076 30e0        CPI  R30,0
7
000077 f061        BREQ _0x6
8
;    0000 0016         *WritePtr++=*readptr++;
9
000078 01f3        MOVW R30,R6
10
000079 9631        ADIW R30,1
11
00007a 013f        MOVW R6,R30
12
00007b 9731        SBIW R30,1
13
00007c 010f        MOVW R0,R30
14
00007d 01d8        MOVW R26,R16
15
                +
16
00007e 5f0f     +SUBI R16 , LOW ( - 1 )
17
00007f 4f1f     +SBCI R17 , HIGH ( - 1 )
18
                   __ADDWRN 16,17,1
19
000080 91ec        LD   R30,X
20
000081 01d0        MOVW R26,R0
21
000082 93ec        ST   X,R30
22
;    0000 0017   }
23
000083 cff0        RJMP _0x4
24
                 _0x6:
25
26
27
;Optimierung SIZE
28
;    0000 0015     while(size--) {
29
                 _0x4:
30
000074 2fe3        MOV  R30,R19
31
000075 5031        SUBI R19,1
32
000076 30e0        CPI  R30,0
33
000077 f061        BREQ _0x6
34
;    0000 0016         *WritePtr++=*readptr++;
35
000078 01f3        MOVW R30,R6
36
000079 9631        ADIW R30,1
37
00007a 013f        MOVW R6,R30
38
00007b 9731        SBIW R30,1
39
00007c 010f        MOVW R0,R30
40
00007d 01d8        MOVW R26,R16
41
                +
42
00007e 5f0f     +SUBI R16 , LOW ( - 1 )
43
00007f 4f1f     +SBCI R17 , HIGH ( - 1 )
44
                   __ADDWRN 16,17,1
45
000080 91ec        LD   R30,X
46
000081 01d0        MOVW R26,R0
47
000082 93ec        ST   X,R30
48
;   0000 0017   }
49
000083 cff0        RJMP _0x4
50
                 _0x6:

von 900ss (900ss)


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
1
; Optimierung -O3
2
    while(size--) {
3
  b4:  2f 3f         cpi  r18, 0xFF  ; 255
4
  b6:  a1 f0         breq  .+40       ; 0xe0 <main+0x4e>
5
  b8:  df 01         movw  r26, r30
6
  ba:  30 e0         ldi  r19, 0x00  ; 0
7
  bc:  2f 5f         subi  r18, 0xFF  ; 255
8
  be:  3f 4f         sbci  r19, 0xFF  ; 255
9
  c0:  2e 0f         add  r18, r30
10
  c2:  3f 1f         adc  r19, r31
11
  c4:  e0 91 66 00   lds  r30, 0x0066
12
  c8:  f0 91 67 00   lds  r31, 0x0067
13
        *WritePtr++=*readptr++;
14
  cc:  8d 91         ld  r24, X+
15
  ce:  81 93         st  Z+, r24
16
  d0:  f0 93 67 00   sts  0x0067, r31
17
  d4:  e0 93 66 00   sts  0x0066, r30
18
19
    RxReadPtr=data;
20
    WritePtr = target;
21
22
    while(size--) {
23
  d8:  a2 17         cp  r26, r18
24
  da:  b3 07         cpc  r27, r19
25
  dc:  b9 f7         brne  .-18       ; 0xcc <main+0x3a>
26
  de:  fd 01         movw  r30, r26
27
        *WritePtr++=*readptr++;
28
  }
29
30
; Optimierung -Os
31
  be:  0b c0         rjmp  .+22       ; 0xd6 <main+0x44>
32
33
    while(size--) {
34
        *WritePtr++=*readptr++;
35
  c0:  89 91         ld  r24, Y+
36
  c2:  e0 91 66 00   lds  r30, 0x0066
37
  c6:  f0 91 67 00   lds  r31, 0x0067
38
  ca:  81 93         st  Z+, r24
39
  cc:  f0 93 67 00   sts  0x0067, r31
40
  d0:  e0 93 66 00   sts  0x0066, r30
41
  d4:  91 50         subi  r25, 0x01  ; 1
42
43
    RxReadPtr=data;
44
    WritePtr = target;
45
46
47
    while(size--) {
48
  d6:  99 23         and  r25, r25
49
  d8:  99 f7         brne  .-26       ; 0xc0 <main+0x2e>
50
        *WritePtr++=*readptr++;
51
  }

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


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.

von 900ss (900ss)


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

von schmocka (Gast)


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?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Das Middleend (4.3.2 mit -Os) macht aus dem Code folgendes:
1
;; Function foo (foo)
2
3
foo ()
4
{
5
  unsigned char size;
6
  unsigned char * readptr;
7
  unsigned char * WritePtr.0;
8
9
<bb 2>:
10
  RxReadPtr = &data;
11
  WritePtr = &target;
12
  size = data[0] + 1;
13
  readptr = &data;
14
  goto <bb 4>;
15
16
<bb 3>:
17
  WritePtr.0 = WritePtr;
18
  *WritePtr.0 = MEM[base: readptr];
19
  WritePtr = WritePtr.0 + 1;
20
  readptr = readptr + 1;
21
22
<bb 4>:
23
  if (readptr != (unsigned char *) (unsigned int) (&data + (unsigned int) size))
24
    goto <bb 3>;
25
  else
26
    goto <bb 5>;
27
28
<bb 5>:
29
  RxReadPtr = readptr;
30
  return;
31
32
}

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.

von (prx) A. K. (prx)


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.

von (prx) A. K. (prx)


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.

von Stefan B. (stefan) Benutzerseite


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?

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


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.

von Shagoon (Gast)


Lesenswert?

gcc 4.3.2 erzeugt mit
1
avr-gcc -S Optimizer.c -O3
1
.L5:
2
        ld r24,X+
3
        st Z+,r24
4
        sts (WritePtr)+1,r31
5
        sts WritePtr,r30
6
        subi r25,1
7
        brcc .L5

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

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


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.

von Johann L. (gjlayde) Benutzerseite


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.

von (prx) A. K. (prx)


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.

von Dirk (Gast)


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.

von Johann L. (gjlayde) Benutzerseite


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.

von (prx) A. K. (prx)


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/Optimize-Options.html

von Dirk (Gast)


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?

von (prx) A. K. (prx)


Lesenswert?

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

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.