Forum: Compiler & IDEs GCC: code funktioniert bei -O, funktioniert nicht bei -Os


von Roland B. (micfan)


Lesenswert?

Hallo,
haette da eine Frage an die Experts..
Bei der Fehlersuche habe ich festgestellt, dass mein Programm ohne 
Optimierung, d.h. mit -O funktioniert, mit der Optimierung -Os nicht. 
Ich habe das Problem separiert, das Beispiel ist jetzt zwar funktionell 
sinnfrei, aber das Problem laessst sich so nachvollziehen.

Ich habe festgestellt, dass das Programm immer laeuft wenn die Variable 
"dow" entweder ausserhalb von main() oder static deklariert wird. D.h. 
die Optimierung spielt keine Rolle.

Im folgenden Beispiel ist die Variable "dow" so definiert, dass das 
Problem auftritt, d.h. die "NOP" Anweisung wird nicht erreicht. In 
meinem echten Projekt fuehrt dieser Effekt dazu, dass die Variable "dow" 
nicht gesetzt wird, d.h. auf 0 bleibt. Mein workaround ist zurzeit, die 
Variable als static zu deklarieren.

Ich verwende:
XP, AVRStudio 4.16, WinAVR-20090313, avr libc 1.6.6, ATMega644p

Ich hoffe ich konnte das Problem halbwegs nachvollziehbar beschreiben.
Vielen Dank fuer evtl. Hinweise!
Gruss
Roland

#include <avr/io.h>
#define  NOP  asm volatile("nop"::);

unsigned int tag=4096;

//unsigned char dow; <-- ok

int main (void)
{
  //static unsigned char dow;  <-- ok
  unsigned char dow;           <-- nicht ok !

  dow = (unsigned char) ((tag >> 12) & 0x000F);
  dow++;
  NOP; <-- Breakpoint im debugger
};

von Peter (Gast)


Lesenswert?

leider ist das Beispiel nicht sinnvoll, die Variable dow wird ja nicht 
gebraucht also wird sie vermutlich komplett weg optimiert.

von Roland B. (micfan)


Lesenswert?

ja ok, hier ist die original Routine, vielleicht hilft das weiter. Mit 
dem Beispiel habe ich es sicher uebertrieben..

void disp_wochentag (unsigned int tag)
{
  char buf[12];
  static unsigned char dow;   <-- dow wird richtig berechnet
  //unsigned char dow;        <-- dow bleibt auf 0

  dow = (unsigned char) ((tag >> 12) & 0x000F);
  dow2ascii(dow, buf);

  backcolor = BLUE;
  textcolor = WHITE;
  lcd_puts(buf);
}

von Peter (Gast)


Lesenswert?

kannst du mal in beiden Fällen den erzeugen asm code zeigen?

von Peter (Gast)


Lesenswert?

Nachtrag: Ich kann mir nicht vorstellen, das ist bei diesem beispiel 
wirklich nicht geht. Ich glaube das Problem ensteht erst in deinen 
kompletten programm.

Bei Static bleibt der Inhalt von dow auch nach den ende der prozedure 
disp_wochentag erhalten. Ich glaube der Fehler ist woanders. z.b. in 
dow2ascii(dow, buf);

von Roland B. (micfan)


Lesenswert?

Hier die Routine mit -Os und static fuer "dow"
void disp_wochentag (unsigned int tag)
{
  char buf[12];
  static unsigned char dow;
  //unsigned char dow;

  dow = (unsigned char) ((tag >> 12) & 0x000F);
  dow2ascii(dow, buf);

  backcolor = BLUE;
  textcolor = WHITE;
  lcd_puts(buf);
}

@00001ABC: disp_wochentag
403:      {
+00001ABC:   930F        PUSH      R16            Push register on stack
+00001ABD:   931F        PUSH      R17            Push register on stack
+00001ABE:   93DF        PUSH      R29            Push register on stack
+00001ABF:   93CF        PUSH      R28            Push register on stack
+00001AC0:   B7CD        IN        R28,0x3D       In from I/O location
+00001AC1:   B7DE        IN        R29,0x3E       In from I/O location
+00001AC2:   972C        SBIW      R28,0x0C       Subtract immediate 
from word
+00001AC3:   B60F        IN        R0,0x3F        In from I/O location
+00001AC4:   94F8        CLI                      Global Interrupt 
Disable
+00001AC5:   BFDE        OUT       0x3E,R29       Out to I/O location
+00001AC6:   BE0F        OUT       0x3F,R0        Out to I/O location
+00001AC7:   BFCD        OUT       0x3D,R28       Out to I/O location
408:        dow = (unsigned char) ((tag >> 12) & 0x000F);
+00001AC8:   9592        SWAP      R25            Swap nibbles
+00001AC9:   709F        ANDI      R25,0x0F       Logical AND with 
immediate
+00001ACA:   9390016A    STS       0x016A,R25     Store direct to data 
space
409:        dow2ascii(dow, buf);
+00001ACC:   2F89        MOV       R24,R25        Copy register
+00001ACD:   018E        MOVW      R16,R28        Copy register pair
+00001ACE:   5F0F        SUBI      R16,0xFF       Subtract immediate
+00001ACF:   4F1F        SBCI      R17,0xFF       Subtract immediate 
with carry
+00001AD0:   01B8        MOVW      R22,R16        Copy register pair
+00001AD1:   940E1A96    CALL      0x00001A96     Call subroutine
411:        backcolor = BLUE;
+00001AD3:   E18F        LDI       R24,0x1F       Load immediate
+00001AD4:   E090        LDI       R25,0x00       Load immediate
+00001AD5:   93900C33    STS       0x0C33,R25     Store direct to data 
space
+00001AD7:   93800C32    STS       0x0C32,R24     Store direct to data 
space
412:        textcolor = WHITE;
+00001AD9:   EF8F        SER       R24            Set Register
+00001ADA:   EF9F        SER       R25            Set Register
+00001ADB:   93900C38    STS       0x0C38,R25     Store direct to data 
space
+00001ADD:   93800C37    STS       0x0C37,R24     Store direct to data 
space
413:        lcd_puts(buf);
+00001ADF:   01C8        MOVW      R24,R16        Copy register pair
+00001AE0:   940E263D    CALL      0x0000263D     Call subroutine
414:      }

und jetzt ohne static
void disp_wochentag (unsigned int tag)
{
  char buf[12];
  //static unsigned char dow;
  unsigned char dow;

  dow = (unsigned char) ((tag >> 12) & 0x000F);
  dow2ascii(dow, buf);

  backcolor = BLUE;
  textcolor = WHITE;
  lcd_puts(buf);
}

@00001ABC: disp_wochentag
403:      {
+00001ABC:   930F        PUSH      R16            Push register on stack
+00001ABD:   931F        PUSH      R17            Push register on stack
+00001ABE:   93DF        PUSH      R29            Push register on stack
+00001ABF:   93CF        PUSH      R28            Push register on stack
+00001AC0:   B7CD        IN        R28,0x3D       In from I/O location
+00001AC1:   B7DE        IN        R29,0x3E       In from I/O location
+00001AC2:   972C        SBIW      R28,0x0C       Subtract immediate 
from word
+00001AC3:   B60F        IN        R0,0x3F        In from I/O location
+00001AC4:   94F8        CLI                      Global Interrupt 
Disable
+00001AC5:   BFDE        OUT       0x3E,R29       Out to I/O location
+00001AC6:   BE0F        OUT       0x3F,R0        Out to I/O location
+00001AC7:   BFCD        OUT       0x3D,R28       Out to I/O location
409:        dow2ascii(dow, buf);
+00001AC8:   9582        SWAP      R24            Swap nibbles
+00001AC9:   708F        ANDI      R24,0x0F       Logical AND with 
immediate
+00001ACA:   018E        MOVW      R16,R28        Copy register pair
+00001ACB:   5F0F        SUBI      R16,0xFF       Subtract immediate
+00001ACC:   4F1F        SBCI      R17,0xFF       Subtract immediate 
with carry
+00001ACD:   01B8        MOVW      R22,R16        Copy register pair
+00001ACE:   940E1A96    CALL      0x00001A96     Call subroutine
411:        backcolor = BLUE;
+00001AD0:   E18F        LDI       R24,0x1F       Load immediate
+00001AD1:   E090        LDI       R25,0x00       Load immediate
+00001AD2:   93900C32    STS       0x0C32,R25     Store direct to data 
space
+00001AD4:   93800C31    STS       0x0C31,R24     Store direct to data 
space
412:        textcolor = WHITE;
+00001AD6:   EF8F        SER       R24            Set Register
+00001AD7:   EF9F        SER       R25            Set Register
+00001AD8:   93900C37    STS       0x0C37,R25     Store direct to data 
space
+00001ADA:   93800C36    STS       0x0C36,R24     Store direct to data 
space
413:        lcd_puts(buf);
+00001ADC:   01C8        MOVW      R24,R16        Copy register pair
+00001ADD:   940E263A    CALL      0x0000263A     Call subroutine
414:      }

von Roland B. (micfan)


Lesenswert?

Peter wrote:
> Nachtrag: Ich kann mir nicht vorstellen, das ist bei diesem beispiel
> wirklich nicht geht. Ich glaube das Problem ensteht erst in deinen
> kompletten programm.
>
> Bei Static bleibt der Inhalt von dow auch nach den ende der prozedure
> disp_wochentag erhalten. Ich glaube der Fehler ist woanders. z.b. in
> dow2ascii(dow, buf);

Hallo Peter,
das Problem kann ja direkt im debugger nachvollzogen werden. Ich kann ja 
sehen das dow2ascii(dow, buf) mit dow=0 aufgerufen wird. Jedenfalls in 
meinem "richtigen" Programm. Das Beispielprogramm bleibt in diesem Fall 
"haengen". Ich habe es mit jtag mk2 gestestet.

Gruss
Roland

von Peter (Gast)


Lesenswert?

ich kann es immer noch nicht glauben.

Wenn ich mir den asm anschauen, ist in beiden fällen die gleiche 
Berechnung drin. Bei der 1. Variante wird der Tag in R25 und bei der 2. 
in R24 übergeben. Dann erfolgt aber genau die gleiche berechnung.

Prüfe mal bitte ob in den Register zu begin der Prozedur auf der Tag 
drin steht.
Eventuell doch mal den kompletten quellcode posten.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Roland Berlauer wrote:
> ja ok, hier ist die original Routine, vielleicht hilft das weiter. Mit
> dem Beispiel habe ich es sicher uebertrieben..
>
> void disp_wochentag (unsigned int tag)
> {
>   char buf[12];
>   static unsigned char dow;   <-- dow wird richtig berechnet
>   //unsigned char dow;        <-- dow bleibt auf 0
>
>   dow = (unsigned char) ((tag >> 12) & 0x000F);
>   dow2ascii(dow, buf);
>
>   backcolor = BLUE;
>   textcolor = WHITE;
>   lcd_puts(buf);
> }

Nein, es hilft nicht weiter. Es hagelt Fehler und Warnungen:
1
foo.c: In function 'disp_wochentag':
2
foo.c:4: error: expected expression before '<' token
3
foo.c:8: warning: implicit declaration of function 'dow2ascii'
4
foo.c:10: error: 'backcolor' undeclared (first use in this function)
5
foo.c:10: error: (Each undeclared identifier is reported only once
6
foo.c:10: error: for each function it appears in.)
7
foo.c:10: error: 'BLUE' undeclared (first use in this function)
8
foo.c:11: error: 'textcolor' undeclared (first use in this function)
9
foo.c:11: error: 'WHITE' undeclared (first use in this function)
10
foo.c:12: warning: implicit declaration of function 'lcd_puts'
11
foo.c:1: warning: unused parameter 'tag'

Wie soll man das Zeug nachvollziehen?
Wie wär's mit einem Testfall?

Johann

von (prx) A. K. (prx)


Lesenswert?

Das sieht schwer nach Compiler-Bug aus. Ich kann es reproduzieren. 
Allerdings tritt der Fehler bei mir (Linux, 4.3.3) auch bei -O auf.

von (prx) A. K. (prx)


Lesenswert?

Testcase:
1
void g(unsigned char);
2
3
void f1(unsigned x)
4
{
5
        unsigned char y;
6
        y = (x >> 12) & 0x0F;
7
        g(y);
8
}
9
10
void f2(unsigned x)
11
{
12
        static unsigned char y;
13
        y = (x >> 12) & 0x0F;
14
        g(y);
15
}

von Roland B. (micfan)


Lesenswert?

Johann L. wrote:
> Roland Berlauer wrote:
>> ja ok, hier ist die original Routine, vielleicht hilft das weiter. Mit
>> dem Beispiel habe ich es sicher uebertrieben..
>>
>> void disp_wochentag (unsigned int tag)
>> {
>>   char buf[12];
...........
>> }
>
> Nein. Es hagelt Fehler:
>
>
1
................
2
>
>
> Wie soll man das Zeug nachvollziehen?
> Wie wär's mit einem Testfall?
>
> Johann

Hallo Johann,
deshalb hatte ich doch gleich als erstes ein Beispiel gepostet..

von Roland B. (micfan)


Lesenswert?

Peter wrote:
> ich kann es immer noch nicht glauben.
>
> Wenn ich mir den asm anschauen, ist in beiden fällen die gleiche
> Berechnung drin. Bei der 1. Variante wird der Tag in R25 und bei der 2.
> in R24 übergeben. Dann erfolgt aber genau die gleiche berechnung.
>
> Prüfe mal bitte ob in den Register zu begin der Prozedur auf der Tag
> drin steht.
> Eventuell doch mal den kompletten quellcode posten.

Das habe ich ueberprueft, z.B. wird die Routine mit tag=4096 aufgerufen, 
fuer dow wird dann 1 berechnet, bei Deklaration von dow als static.

Habe es nach allen Richtungen im Debugger getestet.

von Peter (Gast)


Lesenswert?

Wiegesagt der asm code sollte gehen, wenn wir dir helfen sollen brauchen 
wir etwas mehr code - in denke immer noch der Aufruf ist falsch.

Du sollte schauen ob in den Registern R24 bzw R25 auf der Wert für den 
Tag enthalten ist.

Rufe doch mal bitte die funktion

disp_wochentag(4096)

auf. Also wirklich mit einer Konstante und schau was den passiert. Wenn 
das auch nicht geht, schicke bitte auch den asm code von dem Aufruf mit.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. wrote:
> Testcase:

Ok, danke. Es ist ein Bug. Der Fehler passiert in Pass .166r.split1

In .163.ce2 ist noch alles Ok:
1
(insn 8 20 9 2 foo.c:7 (set (reg:QI 24 r24)
2
        (lshiftrt:QI (reg:QI 25 r25 [ x+1 ])
3
            (const_int 4 [0x4]))) 63 {*lshrqi3_const4} (expr_list:REG_DEAD (reg:QI 25 r25 [ x+1 ])
4
        (nil)))

split1 löscht die Insn und macht daraus
1
(insn 22 20 23 2 foo.c:7 (set (reg:QI 24 r24)
2
        (unspec:QI [
3
                (reg:QI 24 r24)
4
            ] 2)) -1 (nil))

was offenbar falsch ist. In der Version ist swap noch als unspec 2 
implementiert (UNSPEC_SWAP).

Johann

von Roland B. (micfan)


Lesenswert?

Peter wrote:
> Wiegesagt der asm code sollte gehen, wenn wir dir helfen sollen brauchen
> wir etwas mehr code - in denke immer noch der Aufruf ist falsch.
>
> Du sollte schauen ob in den Registern R24 bzw R25 auf der Wert für den
> Tag enthalten ist.
>
> Rufe doch mal bitte die funktion
>
> disp_wochentag(4096)
>
> auf. Also wirklich mit einer Konstante und schau was den passiert. Wenn
> das auch nicht geht, schicke bitte auch den asm code von dem Aufruf mit.

ok Peter, hier ein groesserer Auszug, der sich compilieren laesst. In 
dieser Fassung wird dow richtig berechnet. Sobald man "static" weglaesst 
entsteht das Problem.

#include <avr/io.h>
#include <avr/pgmspace.h>

#define  NOP  asm volatile("nop"::);
#define ANY_DAY     8

const char dow0[] PROGMEM = "?";
const char dow1[] PROGMEM = "Montag";
const char dow2[] PROGMEM = "Dienstag";
const char dow3[] PROGMEM = "Mittwoch";
const char dow4[] PROGMEM = "Donnerstag";
const char dow5[] PROGMEM = "Freitag";
const char dow6[] PROGMEM = "Samstag";
const char dow7[] PROGMEM = "Sonntag";
const char dow8[] PROGMEM = "taeglich";

PGM_P daytab[] PROGMEM = { dow0, dow1, dow2, dow3, dow4, dow5, dow6, 
dow7, dow8 };


void dow2ascii(unsigned char dow, char *s)
{
  PGM_P p;

  if(dow <= ANY_DAY)
    memcpy_P(&p, &daytab[dow], sizeof(PGM_P));  // ok, Tag holen
  else
    memcpy_P(&p, &daytab[0], sizeof(PGM_P));    // Fehleranzeige

  strcpy_P(s, p);
}


void disp_wochentag (unsigned int tag)
{
  char buf[12];
  static unsigned char dow;   // <-- ok
  //unsigned char dow;            // <-- nicht ok

  dow = (unsigned char) ((tag >> 12) & 0x000F);
  dow2ascii(dow, buf);      // dow=1, in buf steht "Montag" bei tag=4096

  NOP;  // <-- breakpoint

  //lcd_puts(buf);
}


int main (void)
{
  disp_wochentag(4096);
  while(1) {};
};

von (prx) A. K. (prx)


Lesenswert?

@Roland,Peter: Ohne eure Diskussion unterbrechen zu wollen: Der Fall ist 
bereits geklärt. Offen ist nur, wer sich die Mühe mit bugzilla macht.

@Roland: Entweder du bleibst bei -O, oder du suchst dir eine ältere 
WinAVR Version, in der das Problem nicht auftritt.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Roland Berlauer wrote:

> ok Peter, hier ein groesserer Auszug, der sich compilieren laesst. In
> dieser Fassung wird dow richtig berechnet. Sobald man "static" weglaesst
> entsteht das Problem.

Es ist, wie gesagt, ein Compilerfehler. Der Fehler tritt auch auf

-- in WinAVR-20080512
-- logische Rechtsshifts um 12, 13 und 14
-- wahlscheinlich auch bei Linksshifts um 12, 13, 14, wobei Testfällt 
schwerer zu erzeugen sein dürften
-- für alle AVR-Derivate

Wie es aussieht, liefert die gcc-Option -fno-split-wide-types einen 
Workaround.

Johann

von Roland B. (micfan)


Lesenswert?

A. K. wrote:
> @Roland,Peter: Ohne eure Diskussion unterbrechen zu wollen: Der Fall ist
> bereits geklärt. Offen ist nur, wer sich die Mühe mit bugzilla macht.
>
> @Roland: Entweder du bleibst bei -O, oder du suchst dir eine ältere
> WinAVR Version, in der das Problem nicht auftritt.

Hallo A. K,
Peter und Johann,
vielen Dank fuer die schnelle Klaerung! Ich selbst habe zuwenig 
Erfahrung, als dass ich mich gewagt haette von einem compiler bug zu 
sprechen. Deshalb ist es sicherlich zielfuehrender wenn das jemand von 
euch meldet. Die Ausfuehrungen von Johann hatte nicht so wirklich 
verstanden .. :-)
Danke nochmals.

Gruss
Roland

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. wrote:
> @Roland,Peter: Ohne eure Diskussion unterbrechen zu wollen: Der Fall ist
> bereits geklärt. Offen ist nur, wer sich die Mühe mit bugzilla macht.

Schon passiert.

Johann

von (prx) A. K. (prx)


Lesenswert?

Johann L. wrote:

> -- in WinAVR-20080512

Sieh an! Bemerkenswert, dass sich ein Bug dieser Qualität so lang 
verstecken konnte. Vielleicht weil sich rumgesprochen hat, dass 
-fno-split-wide-types ohnehin nützlich ist.

von Roland B. (micfan)


Lesenswert?

Johann L. wrote:
> Roland Berlauer wrote:
>
>> ok Peter, hier ein groesserer Auszug, der sich compilieren laesst. In
>> dieser Fassung wird dow richtig berechnet. Sobald man "static" weglaesst
>> entsteht das Problem.
>
> Es ist, wie gesagt, ein Compilerfehler. Der Fehler tritt auch auf
>
> -- in WinAVR-20080512
> -- logische Rechtsshifts um 12, 13 und 14
> -- wahlscheinlich auch bei Linksshifts um 12, 13, 14, wobei Testfällt
> schwerer zu erzeugen sein dürften
> -- für alle AVR-Derivate
>
> Wie es aussieht, liefert die gcc-Option -fno-split-wide-types einen
> Workaround.
>
> Johann
Hallo Johann,
war eine Ueberschneidung. Ich war damit beschaeftigt noch ein "Testcase" 
zusammen zubasteln. Dein Hinweis "gcc-Option -fno-split-wide-types" habe 
ich gleich ausprobiert. Super, es funktioniert.
Nochmals Danke

von (prx) A. K. (prx)


Lesenswert?

Johann L. wrote:

> Schon passiert.

Welche Nummer?

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Hab's direkt in die avr-gcc-list gepostet. Ist einfacher und direkter, 
da lesen Eric und Anatoly ja mit. Bis das im Web-Archiv erscheint, 
dauert's allerdings bis zu 2 Stunden.

http://lists.gnu.org/archive/html/avr-gcc-list/2009-03/

Um so erstaunlicher das ganze, weil es schon mit
1
char foo (unsigned  x)
2
{
3
    return x >> 12;
4
}

raschelt im Gebälk.

Johann

von (prx) A. K. (prx)


Lesenswert?

Das hatte ich auch angenommen als ich das sah. Deshalb ja mein 
Erstaunen.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. wrote:
> Das sieht schwer nach Compiler-Bug aus. Ich kann es reproduzieren.
> Allerdings tritt der Fehler bei mir (Linux, 4.3.3) auch bei -O auf.

Was sagt denn -v? Ich kann den Fehler mit 4.3.3 unter Linux nicht 
nachvollziehen. avr-gcc hab ich erzeugt aus svn gcc_4_3_3_release mit
gcc = 4.0.2
gmp = 4.2.2
mpfr = 2.3.1

Johann

von (prx) A. K. (prx)


Lesenswert?

Ich hatte den nicht selbst erzeugt, sondern vor ein paar Monaten aus dem 
damaligen debian unstable installiert (4.3.3-1). Wird von mir aber nicht
produktiv eingesetzt, sondern nur für solche Tests.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

A. K. wrote:
> Ich hatte den nicht selbst erzeugt, sondern vor ein paar Monaten aus dem
> damaligen debian unstable installiert (4.3.3-1). Wird von mir aber nicht
> produktiv eingesetzt, sondern nur für solche Tests.

Hast du wenigstens die Ausgabe von -v? Oder vielleicht sogar die 
svn-Version oder Tag? Und sind da irgendwelche Patches drinne?

Momentan sieht's eher so aus als wär's ein Bug im Middleend, und nicht 
im Backend.

Johann

von (prx) A. K. (prx)


Lesenswert?

Geduld. -v kommt noch.

von (prx) A. K. (prx)


Lesenswert?

Wird nicht genauer, sorry. gcc -v sagt 4.3.3 und sonst nix, apt sagt 
4.3.3-1 (http://packages.debian.org/en/sid/gcc-avr).

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.