Forum: Compiler & IDEs Compiler-Optimierung bei Register-Variablen


von Ulrich B. (ubien)


Angehängte Dateien:

Lesenswert?

Hallo,

ich bin am verzweifeln! Google und auch die Suche hier im Forum hat mir 
nicht weiter geholfen.

Ich möchte Variablen in einem Register ablegen. Leider optimiert der 
Compiler die Zugriffe auf die Variable komplett weg. Hier das auf das 
Minimum reduzierte Testprogramm (Optimierungseinstellung -Os, wie bei 
µC-Programme üblich):
1
register unsigned char Data asm("r6");
2
3
int main(void)
4
{ while(1)
5
  { Data++;
6
  }
7
}
 führt zu
1
int main(void)
2
{ while(1)
3
  30:  ff cf         rjmp  .-2        ; 0x30 <main>

Deklariere ich "Data" als
1
volatile unsigned char Data;
 erhalte ich das erwartete Ergebnis:
1
int main(void)
2
{ while(1)
3
  { Data++;
4
  40:  80 91 60 00   lds  r24, 0x0060
5
  44:  8f 5f         subi  r24, 0xFF  ; 255
6
  46:  80 93 60 00   sts  0x0060, r24
7
  4a:  fa cf         rjmp  .-12       ; 0x40 <main>
Die Speicherzugriffe möchte ich mir aber gern ersparen. Wenn man bei der 
Register-Deklaration ein "volatile" hinzufügt, ändert sich außer einer 
zusätzlichen Warnung nichts.

Ich benutze das Atmel-Studio in der Version 6.1. Das komplette Projekt 
habe ich als Datei angefügt.

Benutzen möchte ich solch einen Code in einem Projekt, bei dem eine in 
Assembler geschriebene ISR einen Wert in einem Register ablegt.

Wie kann ich den Compiler dazu überreden, den Registerinhalt zu ändern?


Viele Grüße
Ulrich

von Karl H. (kbuchegg)


Lesenswert?

Ulrich Bien schrieb:

> Ich möchte Variablen in einem Register ablegen.

Das möchtest du eigentlich in den meisten Fällen genau nicht tun.
Zumindest dann nicht, wenn das Programm etwas komplexer wird.
Denn zum einen 'klaust' du damit dem Compiler ein Register, welches er 
zum Arbeiten benötigt, zum anderen wissen Bibliotheksfunktionen nichts 
davon, dass du 1 Register für deine exklusive Verwendung abgezwackt hast 
und werden dir bei einem Aufruf beinhart den Registerinhalt 
zerschiessen.

> Benutzen möchte ich solch einen Code in einem Projekt, bei dem eine in
> Assembler geschriebene ISR einen Wert in einem Register ablegt.

Schreib lieber die Assembler Routine so um, dass sie sich an die 
Gepflogenheiten deines Compiler hält und den Wert nicht in einem 
Register ablegt, sondern (so wie das auf deinem Compiler vorgesehen ist) 
auf eine normale Variable zugreift.

Alternativ: schreib die ISR in regulärem C.

: Bearbeitet durch User
von marixstorm (Gast)


Lesenswert?

Ulrich Bien schrieb:
> Wie kann ich den Compiler dazu überreden, den Registerinhalt zu ändern?
1
register unsigned char Data asm("r6");
2
3
int main(void)
4
{
5
  while(1)
6
  {
7
    asm volatile (
8
      "subi %[data],0xff\n\t"
9
      : [data] "+d" (Data)
10
      :
11
    )
12
  }
13
}

von Axel S. (a-za-z0-9)


Lesenswert?

Ulrich Bien schrieb:

> Ich möchte Variablen in einem Register ablegen. Leider optimiert der
> Compiler die Zugriffe auf die Variable komplett weg.

> register unsigned char Data asm("r6");
>
> int main(void)
> { while(1)
>   { Data++;
>   }
> }

Ja. Und?

> Benutzen möchte ich solch einen Code in einem Projekt, bei dem eine in
> Assembler geschriebene ISR einen Wert in einem Register ablegt.

Dann mach doch. Wenn du die Variable richtig verwendest, kann der 
Compiler die Variable auch nicht wegoptimieren. Das Problem ist nicht 
der Compiler sondern dein ungeeigneter Testcode.


XL

von Ulrich B. (ubien)


Lesenswert?

Karl Heinz schrieb:

> Das möchtest du eigentlich in den meisten Fällen genau nicht tun.
> ...
> Schreib lieber die Assembler Routine so um, dass sie sich an die
> Gepflogenheiten deines Compiler hält und den Wert nicht in einem
> Register ablegt, sondern (so wie das auf deinem Compiler vorgesehen ist)
> auf eine normale Variable zugreift.

Wenn ich das tun wollte, hätte ich nicht fragen müssen:-( Trotzdem danke 
für die schnelle Antwort.

> Zumindest dann nicht, wenn das Programm etwas komplexer wird.
> Denn zum einen 'klaust' du damit dem Compiler ein Register, welches er
> zum Arbeiten benötigt, zum anderen wissen Bibliotheksfunktionen nichts
> davon, dass du 1 Register für deine exklusive Verwendung abgezwackt hast
> und werden dir bei einem Aufruf beinhart den Registerinhalt
> zerschiessen.
> ...

Original-Zitat aus der AVR-libc-Dokumentation: "Typically, it should be 
safe to use r2 through r7 that way." Bei der Benutzung von r8 bis r15 
sollte man schon etwas mehr aufpassen.
http://www.nongnu.org/avr-libc/user-manual/FAQ.html#faq_regbind

@marixstorm: Vielen Dank, das funktioniert. Jedoch würde ich gern auf 
die Nutzung von Assembler-Code im Hauptprogramm verzichten.

@Axel Schwenke: Vielen für die hilfreiche Antwort!

: Bearbeitet durch User
von Johann L. (gjlayde) Benutzerseite


Lesenswert?

Ulrich Bien schrieb:
> @marixstorm: Vielen Dank, das funktioniert. Jedoch würde ich gern auf
> die Nutzung von Assembler-Code im Hauptprogramm verzichten.

Wie du bereits selbst festgestellt hast können globale Register nicht 
volatile sein.  Du must bei ISR-Code also ziemlich aufpassen bzw. seht 
hässliche asm-Hacks verwenden um das sicher zum Laufen zu bekommen.

von Rolf Magnus (Gast)


Lesenswert?

Ulrich Bien schrieb:
> Leider optimiert der Compiler die Zugriffe auf die Variable komplett weg.

Klar tut er das. Du tust ja mit der Variable nichts anderes, als sie zu 
inkremenieren. Daher ist der Wert, den sie enthält, völlig irelevant für 
dein Programm, und man kann sich das Inkrementieren sparen.

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.