Forum: Compiler & IDEs Verhindern der wegoptimierung von for(;;) beim GCC


von Flo (Gast)


Lesenswert?

Hallo Leute, köönt ihr mir eventuell sagen wie ich bei diesem Code:
1
#include <avr/io.h>
2
#include <stdio.h>
3
#include <inttypes.h>
4
#include <stdint.h>
5
#include <avr/eeprom.h>
6
#include <util/delay.h>
7
#include <avr/interrupt.h>
8
#include <avr/wdt.h>
9
#include <avr/pgmspace.h>
10
11
void main(void) __attribute__((noreturn));
12
13
#define UBRR_VAL ((F_CPU+BAUD*8)/(BAUD*16)-1)   // clever runden
14
#define BAUD 19200L
15
16
uint8_t i=0;
17
char c;
18
char s[10];
19
char input[10];
20
char gcc[] PROGMEM = "Boot up Ready, OS Compiliert am "__DATE__" um "__TIME__" mit GCC Version "__VERSION__"\r\n";
21
22
23
void uart_puts (char *s);
24
int uart_putc(unsigned char c);
25
uint8_t uart_getc(void);
26
void uart_puts_p(const char *text);
27
uint8_t uart_puffer_check(void);//Erkennung für neue Zeichen
28
29
#define max 20
30
volatile uint8_t puffer[max]; 
31
volatile uint8_t* lesezeiger; 
32
volatile uint8_t* schreibzeiger; 
33
34
35
void main(void)
36
{
37
  UCSRB = 1<<TXEN | 1<<RXEN;              // UART TX einschalten UART RX einschalten
38
  UCSRC = 1<<URSEL | 1<<UCSZ1 | 1<<UCSZ0;           // Asynchron 8N1
39
  UBRRH = UBRR_VAL >> 8;
40
  UBRRL = UBRR_VAL & 0xFF;
41
  UCSRB |= (1<<RXCIE);
42
  //uart_puts_p(gcc);
43
44
  lesezeiger=puffer; 
45
  schreibzeiger=puffer;
46
47
  sei();
48
  for(;;)
49
  {
50
    
51
    if(uart_puffer_check()==1)
52
    {
53
      
54
      input[i]=uart_getc();
55
      i++;
56
      if(input[i-1]==0x0d)
57
      {
58
        input[i-1]=0;
59
        i=0;
60
        //uart_puts(input);
61
      }
62
    }
63
    else
64
    {
65
      
66
    }
67
  }
68
}
69
70
uint8_t uart_getc(void)
71
{ 
72
  uint8_t datenbyte=0; 
73
 
74
  if(schreibzeiger!=lesezeiger)
75
  { 
76
      datenbyte=*lesezeiger;//Auslesen des Ringpuffers 
77
      lesezeiger++; 
78
     if(lesezeiger==puffer+max) lesezeiger=puffer; 
79
   } 
80
  return datenbyte; 
81
} 
82
83
int uart_putc(unsigned char c)
84
{
85
    while (!(UCSRA & (1<<UDRE)))
86
    {
87
    }
88
89
    UDR = c;
90
    return 0;
91
}
92
93
void uart_puts (char *s)
94
{
95
    while (*s)
96
    {   
97
        uart_putc(*s);
98
        s++;
99
    }
100
}
101
102
void uart_puts_p(const char *text)
103
{
104
    char Zeichen;
105
 
106
    while (Zeichen = pgm_read_byte(text))
107
    {   /* so lange, wie mittels pgm_read_byte ein Zeichen vom Flash gelesen
108
           werden konnte, welches nicht das "String-Endezeichen" darstellt */
109
 
110
        /* Das gelesene Zeichen über die normalen Kanäle verschicken */
111
        uart_putc(Zeichen);
112
        text++;
113
    }
114
}
115
116
uint8_t uart_puffer_check(void)
117
{ 
118
if(schreibzeiger!=lesezeiger) 
119
  return 1; 
120
else return 0; 
121
} 
122
123
ISR (USART_RXC_vect)
124
{ 
125
    *schreibzeiger=UDR; //empfangenes Datenbyte abspeichern 
126
  uart_putc(*schreibzeiger);
127
    schreibzeiger++; 
128
    if(schreibzeiger==puffer+max) 
129
    schreibzeiger=puffer; 
130
}

verhindern kann das die For Schleife wegoptimiert wird, der code ist 
noch nicht fertig ,ist erstmal nur zum rumspielen

Danke im Vorraus

Flo

: Verschoben durch Admin
von Sven P. (Gast)


Lesenswert?

Die wird nicht wegoptimiert.

von Flo (Gast)


Lesenswert?

Also es sieht zumindes so aus ,da der Teil in der Schleife nicht 
ausgeführt wird und keine ausgabe kommt.Die stelle //uart_puts(input); 
ist im übrigen nicht auskommentiert in der Version die ich Flashe.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird, 
dann:
1
for(;;)
2
{
3
    __asm__ __volatile__ (""::);
4
}

Das geht zumindest für alle GCC. Aber am erzeugten Maschiinencode wirst 
du da kein Unterschied sehen, weil eine Schleife über nix ist immer noch 
eine Schleife über nix. Well also Oprtationen in der Schleife 
drinstehen, die keine Wirkung auf die abstrakte Maschine haben, kann 
ein Compiler diese dennoch rauswerfen.

Johann

von Stefan E. (sternst)


Lesenswert?

Johann L. schrieb:
> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,

Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich 
würde das den Programmablauf unzulässig verändern.

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Ja, stimmt. Aber auch bei sowas bringt es nicht unbedingt was:
1
for (int i=0; i < 100; i++)
2
{
3
    __asm__ __volatile__ (""::);
4
}

Der Compiler könne die Schleife aufrollen, und 100*nix ist eben auch 
nix...

Johann

von Ingo E. (ogni42)


Lesenswert?

schau mal in den Code:

schreibzeiger == lesezeiger! Damit gibt Deine checkroutine immer 0 
zurück => die if aberfrage in der for(;;) Schleife ist immer false. Und 
uart_getc wird erst innerhalb der if Abfrage ausgeführt.

EDIT: Das sei() bringt nicht viel, da Du keine ISRs zur Verfügung 
stellst.

von Sven P. (Gast)


Lesenswert?

Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Dadrauf bezog dein Vorposter sich mit 'Abstrakter Maschine'.

von Stefan E. (sternst)


Lesenswert?

Sven P. schrieb:
> Stefan Ernst schrieb:
>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.
>
> Dadrauf bezog dein Vorposter sich mit 'Abstrakter Maschine'.

Ich verstehe nicht so ganz, was du mir damit sagen willst. Ob die 
Maschine nun abstrakt oder real ist, spielt in diesem Zusammenhang doch 
keine Rolle.

von (prx) A. K. (prx)


Lesenswert?

Das ist in diesem Zusammenhang ein Begriff aus der Informatik, Thema 
Programmiersprachen und Compilerbau.

von Peter D. (peda)


Lesenswert?

Mach den Code als Dateianhang (*.c) und dann sag konkret, welche Zeile 
(Nummer) er Deiner Meinung nach wegoptimiert.

In der Regel hat er aber einen Grund, wenn er das macht. D.h. wenn Du 
ihn durch irgendetwas zwingst, es nicht zu tun, wird trotzdem nichts 
anderes passieren.

Es sei denn, es ist ein volatile-Fehler. Die kann man einfach mit der 
Optimierung -O0 rauskriegen.


Peter

von Karl H. (kbuchegg)


Lesenswert?

Das hier
1
volatile uint8_t* lesezeiger; 
2
volatile uint8_t* schreibzeiger;

sollte zumindest lauten
1
uint8_t* volatile lesezeiger; 
2
uint8_t* volatile schreibzeiger;

damit sich der Compiler bei
1
...
2
if(schreibzeiger!=lesezeiger)
3
...

nicht mit Registerversionen der Pointer zufrieden gibt, die längst 
obsolet sind, weil sie in der ISR verändert wurden.

In Summe solltest du allerdings beides volatile machen: Die Pointer, als 
auch das, worauf die Pointer zeigen:
1
volatile uint8_t* volatile lesezeiger; 
2
volatile uint8_t* volatile schreibzeiger;

Was ist mit der ISR? Wird sie aufgerufen (sprich: kriegst du das Echo 
von dort)? Hast du das gegengechecked, also zb ein anderes Echo 
zurückschicken; Nicht dass du einem lokalen Echo deines Terminals 
aufsitzt.

von Walter (Gast)


Lesenswert?

>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.

habt ihr gelesen was der Originalposter will?

von Walter (Gast)


Lesenswert?

>Sowohl der Pointer selbst, als auch das worauf er zeigt, müssen volatile
>sein.
das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem 
Problem zu tun

wird die ISR überhaupt ausgeführt?

von (prx) A. K. (prx)


Lesenswert?

Walter schrieb:

> das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem
> Problem zu tun

Denke schon, denn der Compiler wird uart_puffer_check() wahrscheinlich 
inlinen und dann feststellen, dass diese Funktion aufgrund seiner 
Kenntnis der Werte der beiden Pointer stets 0 zurück gibt.

von Karl H. (kbuchegg)


Lesenswert?

Walter schrieb:
>>Sowohl der Pointer selbst, als auch das worauf er zeigt, müssen volatile
>>sein.
> das glaube ich jetzt erst Mal nicht, zumindest hat das nichts mit dem
> Problem zu tun

Ach.
Und was denkst du, wird passieren, wenn sich der Compiler
1
    if(uart_puffer_check()==1)
2
3
...
4
5
uint8_t uart_puffer_check(void)
6
{ 
7
if(schreibzeiger!=lesezeiger) 
8
  return 1; 
9
else return 0; 
10
}

dafür entscheidet, die Pointer nicht neu aus dem Speicher zu holen, 
sondern mit Registerversionen derselben den uart_puffer_check 
durchzuführen.
Das kommt dann besonders gut, wenn die ISR (so sie überhaupt aufgerufen 
wird) die Speicherversionen der Pointer verändert, die Überprüfung aber 
mit Registerversionen stattfindet :-)

Variablen, die aus einer ISR heraus verändert werden, müssen volatile 
gemacht werden. schreibzeiger ist eine Variable. Sie wird in der ISR 
verändert und in main() abgefragt. Also muss man sie volatile machen. 
Die Tatsache, dass schreibzeiger ein Pointer ist, spielt dabei erst mal 
keine Rolle. Und die Syntax dafür ... siehe oben.

von Walter (Gast)


Lesenswert?

mit dem bin ich ja einverstanden:
uint8_t* volatile lesezeiger;
uint8_t* volatile schreibzeiger;


aber wofür soll das sein:
volatile uint8_t* volatile lesezeiger;
volatile uint8_t* volatile schreibzeiger;

von Karl H. (kbuchegg)


Lesenswert?

Walter schrieb:
> mit dem bin ich ja einverstanden:
> uint8_t* volatile lesezeiger;
> uint8_t* volatile schreibzeiger;
>
>
> aber wofür soll das sein:
> volatile uint8_t* volatile lesezeiger;
> volatile uint8_t* volatile schreibzeiger;

Dann mach dich mal mit den Regeln vertraut, wie volatile (oder auch 
'const') angewendet werden.

Hinweis:
Bei Pointern ist sowohl bei const als auch bei volatile die Frage zu 
beantworten: Wer ist denn eigentlich const (bzw. volatile)? Der Pointer 
oder das worauf er zeigt? Oder vielleicht beides?

von Michael G. (linuxgeek) Benutzerseite


Lesenswert?

Stefan Ernst schrieb:
> Johann L. schrieb:
>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>
> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
> würde das den Programmablauf unzulässig verändern.

Richtig. Ein Compiler, der so "optimiert" waere fehlerhaft. Und das 
glaube ich hier nicht. Vielleicht hast Du ja einen Programmabsturz 
verursacht...

von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Michael G. schrieb:
> Stefan Ernst schrieb:
>> Johann L. schrieb:
>>> Wenn du eine leere Schleife haben willst, die nicht wegoptimiert wird,
>>
>> Ein leere Endlosschleife wird niemals wegoptimiert werden, schließlich
>> würde das den Programmablauf unzulässig verändern.
>
> Richtig. Ein Compiler, der so "optimiert" waere fehlerhaft.

Wieso? Wenn der Programmfluß nicht an die Stelle kommt kann DCE (dead 
code elimination) auch Endlosschleifen wegwerfen.

Dann sieht man den Code nicht, der da ansonsten übersetzt werden würde. 
Aber Fehler ist das keiner.

Johann

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.