-
        

Seite 1 von 2 12 LetzteLetzte
Ergebnis 1 bis 10 von 14

Thema: GCC deoptimiert

  1. #1
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    25.03.2006
    Ort
    Darmstadt
    Alter
    26
    Beiträge
    522

    GCC deoptimiert

    Anzeige

    Hallo,

    ich habe eine Funktion add(char,char), die mir die Summe der beiden Werte liefert. Nun hat GCC 3.4.6 mit der Optimierung 2,3,s folgendes draus gemacht:
    Code:
      35               	.global	_Z3addcc
      37               	_Z3addcc:
      38               	.LFB42:
      39               	.LM1:
      40               	/* prologue: frame size=0 */
      41               	/* prologue end (size=0) */
      42 0000 962F      		mov r25,r22
      43               	.LBB2:
      44               	.LM2:
      45 0002 980F      		add r25,r24
      46               	.LBE2:
      47               	.LM3:
      48 0004 892F      		mov r24,r25
      49 0006 9927      		clr r25
      50               	/* epilogue: frame size=0 */
      51 0008 0895      		ret
    Es kommt aber noch dicker, Code bei Optimierung 0:
    Code:
    32               	.global	_Z3addcc
      34               	_Z3addcc:
      35               	.LFB42:
      36               	.LM1:
      37               	/* prologue: frame size=2 */
      38 0000 CF93      		push r28
      39 0002 DF93      		push r29
      40 0004 CDB7      		in r28,__SP_L__
      41 0006 DEB7      		in r29,__SP_H__
      42 0008 2297      		sbiw r28,2
      43 000a 0FB6      		in __tmp_reg__,__SREG__
      44 000c F894      		cli
      45 000e DEBF      		out __SP_H__,r29
      46 0010 0FBE      		out __SREG__,__tmp_reg__
      47 0012 CDBF      		out __SP_L__,r28
      48               	/* prologue end (size=10) */
      49 0014 8983      		std Y+1,r24
      50 0016 6A83      		std Y+2,r22
      51               	.LBB2:
      52               	.LM2:
      53 0018 9981      		ldd r25,Y+1
      54 001a 8A81      		ldd r24,Y+2
      55 001c 890F      		add r24,r25
      56 001e 9927      		clr r25
      57               	.LBE2:
      58               	/* epilogue: frame size=2 */
      59 0020 2296      		adiw r28,2
      60 0022 0FB6      		in __tmp_reg__,__SREG__
      61 0024 F894      		cli
      62 0026 DEBF      		out __SP_H__,r29
      63 0028 0FBE      		out __SREG__,__tmp_reg__
      64 002a CDBF      		out __SP_L__,r28
      65 002c DF91      		pop r29
      66 002e CF91      		pop r28
      67 0030 0895      		ret
    Bei der Optimerung 1 kommt jedoch das hier raus:
    Code:
      32               	.global	_Z3addcc
      34               	_Z3addcc:
      35               	.LFB42:
      36               	.LM1:
      37               	/* prologue: frame size=0 */
      38               	/* prologue end (size=0) */
      39               	.LBB2:
      40               	.LM2:
      41 0000 860F      		add r24,r22
      42               	.LBE2:
      43               	.LM3:
      44 0002 9927      		clr r25
      45               	/* epilogue: frame size=0 */
      46 0004 0895      		ret
    Kann mir jemand erklären, wieso GCC bei Opt. 0,2,3,s solch einen Mist produziert? Besonders bei Opt. 0, wo er anscheinend aus dem Hw-Stack einen Sw-Stack macht ???

    MfG Mark

  2. #2
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.08.2005
    Ort
    49.80248 8.59252
    Alter
    33
    Beiträge
    172
    Hm. also ich kann leider kein Assembler. Ich wuerde sagen, dass ist nur aus deiner Sicht Mist. Opt.0 ist btw ueberhaupt keine Optimierung, deswegen ist dieser Code auch am längsten.
    Welche Stufe jetzte fuer max. Geschwindigkeit, Speed oder beides steht, weiss ich leider nicht auswendig. Aber ich kann mir eben gut vorstellen, das ein auf Geschwindigkeit optimierter Code eben haesslich aussieht. Verstehste?

  3. #3
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    25.03.2006
    Ort
    Darmstadt
    Alter
    26
    Beiträge
    522
    Zitat Zitat von kater
    Hm. also ich kann leider kein Assembler. Ich wuerde sagen, dass ist nur aus deiner Sicht Mist.
    Nein, das ist wirklich Mist, denn der Code bei der Oprimierungsstufe 1 ist der schnellste, der kürzeste und der einfachste. Im grunde muss die Funktion nichts anderes tun als r24 mit r22 zu addieren und zurückkehren. Beim Code mit der Opt. 2,3,s wird zuerst r22 nach r25 kopiert, dann wird r25 mir r24 addiert und das Ergebnis dann nach r24 kopiert. Man hätte aber wie bei Opt.1 die beiden Reg einfach sofort addieren können. Bei der opt. 0 blick ich ehrlich gesagt kaum durch, denn dort wird der Stack, für den es die Befehle push und pop gibt manuell angesteuert, das heisst Stackpointer wird zuert in ein Register geladen, dekrementiert und dann wieder in die IO-Register SP gespeichert. Warum in allen drei Fällen r25 gelöscht wird weiss ich auch nicht, aber ich neme an, dass es mit der späteren Registerverwendung des GCC zusammenhängt.

    MfG Mark

  4. #4
    Erfahrener Benutzer Fleißiges Mitglied
    Registriert seit
    01.08.2005
    Ort
    49.80248 8.59252
    Alter
    33
    Beiträge
    172
    Dann ist dein Code einfach zu einfach, zu wenig. Da weiss der GCC nicht was es machen soll, aber da es was machen muss, macht er scheissr

  5. #5
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Warum in allen drei Fällen r25 gelöscht wird weiss ich auch nicht, aber ich neme an, dass es mit der späteren Registerverwendung des GCC zusammenhängt.
    Diese Frage beantwortet hoffentlich ein Auszug aus der avr-libc Dokumentation:
    Return values: 8-bit in r24 (not r25!), 16-bit in r25:r24, up to 32 bits in r22-r25, up to 64 bits in r18-r25. 8-bit return values are zero/sign-extended to 16 bits by the caller (unsigned char is more efficient than signed char - just clr r25).
    Quelle:http://www.nongnu.org/avr-libc/user-...#faq_reg_usage

    Tip: auf www.mikrocontroller.net liest Jörg Wünsch mit, wenn er Dir die Fragen nicht beantworten kann, wer sonst ?

    Gruß Sebastian
    Software is like s e x: its better when its free.
    Linus Torvald

  6. #6
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    25.03.2006
    Ort
    Darmstadt
    Alter
    26
    Beiträge
    522
    Hallo izaseba,

    danke für die Info. Zumindest das mit r25 ist jetzt geklärt. Ich werd mal die Frage auf Mikrocontroller.net stellen, hoffentlcih bekomm ich da eine Antwort drauf, wieso der Code so lang ist.

    MfG Mark

  7. #7
    Super-Moderator Robotik Visionär Avatar von PicNick
    Registriert seit
    23.11.2004
    Ort
    Wien
    Beiträge
    6.836
    Der Code bei "0" stellt den Standard dar. Die Call argumente werden auf den Stack gestellt, dadurch sind sie für alle folgenden Befehle in der Funktion an einer definierten Stelle ( y+1, y+2). (Bei anderen Compilern macht das oft schon der "CALL" und nicht die Funktion selbst)

    Die Optimierung checkt aber dann den konkreten Einzelfall. Und kommt drauf, daß obiges eben nicht erforderlich ist. Ja, und dann bleibt eben nurmehr das bißchen Zeugs über, wie in deinem Beispiel bei Opt "1"

    Eine weitere Optimerung schmeißt vielleicht überhaupt die ganze Funktion weg und macht die Addition direkt dort, wo jetzt der "Call" steht. Das wär dann noch flotter.

    Wie schon von anderen gesagt: Der "lange" Code ist der standard-Call-mechanismus, der schaut bei einem 8-Bit Miniwuzi eben so aus.
    mfg robert
    Wer glaubt zu wissen, muß wissen, er glaubt.

  8. #8
    Erfahrener Benutzer Robotik Einstein Avatar von SprinterSB
    Registriert seit
    09.06.2005
    Ort
    An der Saar
    Beiträge
    2.801
    Das "clr 25" geht auf das ABI von avr-gcc zurück, weil eine return value promotion gemacht wird, also Werte als 16-Bit zurückgegeben werden.

    Diese Promotion wird selbst dann ausgeführt, wenn die Funktion geinlinet wird.

    Die überflüssigen mov-Instruktionen bei O1, O2 und Os gehen darauf zurück, daß GCC nicht perfekt ist.

    Zeig mal deinen Quellcode.
    Disclaimer: none. Sue me.

  9. #9
    Erfahrener Benutzer Roboter Experte
    Registriert seit
    25.03.2006
    Ort
    Darmstadt
    Alter
    26
    Beiträge
    522
    Hallo,

    danke für Eure Antworten. Der Quellcode ist folgender:
    Code:
    #include <iostream.h>
    #include "MyCode.h"
    
    char add(char a,char b)
    {
    	return a+b;
    }
    
    using std::cout;
    
    int main()
    {
    	System_Init();
    	Uart_Init(38400);
    	while(1)
    	{
    		cout<<static_cast<int>(add(10,20))<<endl;
    	}
    }
    Ich weiss, die Funktion macht keinen Sinn. Ich wollte einfach mal versuchen, eine Funktion in ASM zu schreiben und sie dann mit dem C++-Code zu compilieren. Als dann der Linker meckerte, weil er die Funktion nicht gefunden hat, hab ich es in C++ gemacht, um zu gucken, wie sie heissen mußte, damit sie auch erkannt wird. Jetzt weiss ich, dass sie '_Z3addcc' heißen muss, um sie als char add(char,char) verwenden zu können.

    MfG Mark

  10. #10
    Erfahrener Benutzer Robotik Einstein
    Registriert seit
    08.05.2005
    Ort
    Issum
    Alter
    45
    Beiträge
    2.236
    Nun hab ich mir das selber angeschaut, allerdings in C mit dem Ergebnis kann ich garnicht meckern, Code:
    Code:
    #include <avr/io.h>
    
    
    uint8_t add(uint8_t a,uint8_t b) {
      return a+b;
    }
    
    int main(void) {
    
      uint8_t a=15;
      uint8_t b=10;
      DDRC = 255;
        
      PORTC = add(a,b);
      while(1);
      return 0;
    }
    Das wird aus add gemacht:
    Code:
    uint8_t add(uint8_t a,uint8_t b) {
      8e:	68 0f       	add	r22, r24
      return a+b;
    }
      90:	86 2f       	mov	r24, r22
      92:	99 27       	eor	r25, r25
      94:	08 95       	ret
    Und da alles zu Kompileirzeit bekannt ist wird die Funktion garnicht aufgerufen:
    Code:
    PORTC = add(a,b);
      a2:	89 e1       	ldi	r24, 0x19	; 25
      a4:	85 bb       	out	0x15, r24	; 21
      a6:	ff cf       	rjmp	.-2      	; 0xa6 <main+0x10>
    Das einzigste was hier auffällt, man könnte die Funktion add komplett wegoptimieren, dann wäre es perfekt, aber man kann ja nicht alles haben
    Dann hab ich mir gedacht, ich lese ein Port ein, damit er doch add aufruft:
    Code:
    int main(void) {
    
      uint8_t b=10;
      uint8_t c;
      DDRC = 255;
      c=PINB;
      PORTC = add(c,b);
      while(1);
      return 0;
    }
    Und? Käse, selbst hier ruft er die nicht auf !
    Code:
    c=PINB;
      a2:	86 b3       	in	r24, 0x16	; 22
      PORTC = add(c,b);
      a4:	86 5f       	subi	r24, 0xF6	; 246
      a6:	99 27       	eor	r25, r25
      a8:	85 bb       	out	0x15, r24	; 21
      aa:	ff cf       	rjmp	.-2      	; 0xaa <main+0x14>
    Achso, optimiert wurde mit -Os was anderes benutze ich sowieso nicht.

    Gruß Sebastian

    P.S. avr-gcc 4.1.0
    Software is like s e x: its better when its free.
    Linus Torvald

Seite 1 von 2 12 LetzteLetzte

Berechtigungen

  • Neue Themen erstellen: Nein
  • Themen beantworten: Nein
  • Anhänge hochladen: Nein
  • Beiträge bearbeiten: Nein
  •