mikrocontroller.net

Forum: Compiler & IDEs Optimierung mittels typecast


Autor: Malte Marwedel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Also aus dem Code:
  if (gdurchlauf < (uint8_t)(gtemp & 0x0f)) {
erhalte ich das Assembler Listing:
  .stabn 68,0,63,.LM6-__vector_5
.LM6:
  mov r24,r18
  clr r25
  andi r24,lo8(15)
  andi r25,hi8(15)
  cp r20,r24
  cpc r21,r25
  brge .L5
für mich sieht das so aus als ob der Code fürs Vergleichen von 16Bit
Werten ausgelegt ist.
Soweit ich den Assembler Code richtig verstehe setzt er Register r25
auf Null und führt dann mit den oberen 8Bit von 0x000f eine logische
UND Verknüpfung durch, wobei das Ergebnis in Register 25 gespeichert
wird. Dann werden zweimal jeweils zwei Register irgendwie verglichen
(ich kann halt nicht sonderlich gut Assembler) und abhängig vom
Ergebnis ein Sprung ausgeführt. Nach meiner Überlegung müsste jedoch
Register r25 immer Null sein (0 AND 0 ergibt 0) und somit eigentlich
wegoptimiert werden.
Desweiteren habe ich versucht durch (uint_8t) dem Compiler mitzuteilen
dass 8Bit für die Berechnung genügen, aber der erzeugte Code ist der
gleiche. Alle von mir im obrigen Code Ausschnitt verwendeten Variablen
sind vom Typ uint_8t.
Verstehe ich blos den Code grundlegend falsch oder wie bringe ich gcc
(Aufruf enthält die Anweisung -Os zur Optimierung) dazu den Code zu
optimieren?

Autor: Thorsten (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ist (uint_8t) = (unsigned char) ?

Autor: Malte Marwedel (Gast)
Datum:
Angehängte Dateien:

Bewertung
0 lesenswert
nicht lesenswert
>Ist (uint_8t) = (unsigned char) ?
Ja, uint_8t ist in der standartmäßig mit installierten
avr/include/inttypes.h durch
typedef unsigned char uint8_t;
definiert.

Ich hab jetzt nochmal den kompletten Quelltext angehängt

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

logische Operationen (wie dein gtemp & 0x0f) werden laut C-Standard
immer in 16-Bit (oder in sizeof(int)*8, das weiß ich jetzt gerade nicht
auswendig) ausgeführt.

Matthias

Autor: Malte Marwedel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Dass standartmäßig mit 16Bit gerechnet wird hab ich auch schon gelesen
:-)
Nur wird in
http://www.mikrocontroller.net/forum/read-2-96892.html#96901
beschrieben dass mann allen anschein nach dem Compiler dazu bringen
kann trotzdem mit 8Bit zu rechnen. Und das hab ich mit dem
vorgestelltem (uint8_t) versucht, nur wird dies vom Compiler
ignoriert.
Ich möchte halt die Interrupt Routine möglichst klein und schnell
halten.

Autor: Matthias (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hi

caste doch mal die einzelenen Operatoren (insbesondere die Konstante)
vor der eigentlichen Operation nach uint8_t.

Matthias

Autor: Peter Dannegger (peda)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Damit muß man sich abfinden, der GCC castet oft in Vergleichen und immer
in switch() nach 16 Bit, auch wenn es gar keinen Sinn macht.

Will man das in Vergleichen vermeiden, hilft nur das Ergebins erstmal
einer 8-Bit Variablen zuzuweisen und diese dann zu testen.

Das macht natürlich den Code länger und damit unleserlicher.
Sollte man also nur machen, wenn es wirklich auf das letzte Quentchen
Flash oder die µs ankommt.


Peter

Autor: Malte Marwedel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke, der Tipp die If Verzweigung in zwei Zeilen zu teilen hat es
gebracht. Die Interrupt Routine dürfte jetzt ungefähr 100 Takte weniger
zur Abarbeitung benötigen und da die Routine mehrere Tausend mal pro
Sekunde aufgerufen wird, dürfte dies einiges sparen. Der copilierte
Code wurde um 30Byte kleiner, was bei einem ATMEGA32 aber sicher nicht
sonderlich wichtig ist.

Autor: Harry (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich habe hier ein paar Bemerkungen aus dem Handbuch kopiert:

Why does the compiler compile an 8-bit operation that uses bitwise
operators into a 16-bit operation in assembly?
Bitwise operations in Standard C will automatically promote their
operands to an int, which is (by default) 16 bits in avr-gcc.

To work around this use typecasts on the operands, including literals,
to declare that the values are to be 8 bit operands.

This may be especially important when clearing a bit:

var &= ~mask;  /* wrong way!

The bitwise "not" operator (~) will also promote the value in mask to
an int. To keep it an 8-bit value, typecast before the "not" operator:


var &= (unsigned char)~mask;

Alles klar?

Viele Grüsse
Harry

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
@Harry:
Das dachte ich bisher auch immer. Aber die WINAVR-Version vom April
2004 macht das -je nach angegebenen Options- anders: Aus folgendem
Code:


#define  ov_event  _BV(2)
...
uint8_t my_tmr0_event;
...

  if (my_tmr0_event & ov_event){
    my_tmr0_event &= ~ov_event;
  }


macht der Compiler diesen Output, an dem nur noch das (clr r25) zuviel
ist. Das bleibt aber, egal wieviel und wo ich typecaste:


 193:interrupt.c   ****   if (my_tmr0_event & ov_event){
 323                 .LM17:
 324 0052 842F          mov r24,r20
 325 0054 9927          clr r25
 326 0056 82FF          sbrs r24,2
 327 0058 02C0          rjmp .L6
 194:interrupt.c   ****     my_tmr0_event &= ~ov_event;
 329                 .LM18:
 330 005a 4B7F          andi r20,lo8(-5)


Übersetzt ist das Ganze mit dem Standard-Makefile von Jörg:


Compiling: interrupt.c
avr-gcc -c -mmcu=atmega16 -I. -g -Os -funsigned-char
-funsigned-bitfields -fpack-struct -fshort-enums -Wall
-Wstrict-prototypes -Wa,-adhlns=prn_int.lst  -std=gnu99
-Wp,-M,-MP,-MT,interrupt.o,-MF,.dep/interrupt.o.d interrupt.c -o
interrupt.o


Dieses Verhalten liegt meiner Meinung nach an der -fshort-enums Option:
(Auszug aus Tkinfo -> gcc):


`-fshort-enums'
     Allocate to an `enum' type only as many bytes as it needs for
the
     declared range of possible values.  Specifically, the `enum'
type
     will be equivalent to the smallest integer type which has enough
     room.

     *Warning:* the `-fshort-enums' switch causes GCC to generate
code
     that is not binary compatible with code generated without that
     switch.  Use it to conform to a non-default application binary
     interface.

Stefan

Autor: Fritz Ganter (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo!

Hat sich da schon eine Lösung ergeben? Mein Kollege hat das gleiche
Problem, aber casten hilft nichts, wobei das Problem nur bei Verwendung
von Konstanten auftritt.

213:leuchtturm.c  ****   if ((unsigned char)(c & (unsigned char) 8) ==
0)
 570                 .LM48:
 571 0286 8091 0000     lds r24,c
 572 028a 9927          clr r25
 573 028c 9C01          movw r18,r24
 574 028e 3695          lsr r19
 575 0290 2795          ror r18
 576 0292 3695          lsr r19
 577 0294 2795          ror r18
 578 0296 3695          lsr r19
 579 0298 2795          ror r18
 580 029a 81E0          ldi r24,lo8(1)
 581 029c 90E0          ldi r25,hi8(1)
 582 029e 8227          eor r24,r18
 583 02a0 9327          eor r25,r19
 584 02a2 8170          andi r24,lo8(1)
 585 02a4 9070          andi r25,hi8(1)
 586 02a6 0097          sbiw r24,0
 587 02a8 29F0          breq .L27
 214:leuchtturm.c  ****   {
 215:leuchtturm.c  ****     j++;
 589                 .LM49:
 590 02aa 8091 0000     lds r24,j
 591 02ae 8F5F          subi r24,lo8(-(1))
 592 02b0 8093 0000     sts j,r24
 593                 .L27:
 216:leuchtturm.c  ****   }

Autor: Malte Marwedel (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Wie schon geschrieben, ich habe mich einfach mit zwei Zeilen Quellcode
begnügt.
Aus:
if (gdurchlauf < (gdbyte & 0x03)) {
wurde:
  gtemp = gdbyte & 0x03; //Dies in der If Verzweigung ->16Bit
  if (gdurchlauf < gtemp) {

Autor: Stefan Kleinwort (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Fritz,

mit welchen Optionen hast Du den Code übersetzt  welcher mc  wie ist
c definiert? Bei mir ist cc lokal als unsigned char definiert, dann
kommt folgender Code raus, der eigendlich kürzer nicht sein kann:

116:buskoppler.c  ****   if ((unsigned char)(cc & (unsigned char) 8) ==
0){
 290                 .LM28:
 291 0086 F3FC          sbrc r15,3
 292 0088 02C0          rjmp .L9
 117:buskoppler.c  ****     c = 1;
 294                 .LM29:
 295 008a 81E0          ldi r24,lo8(1)
 296 008c 8983          std Y+1,r24
 297                 .L9:

Übrigens mit der neuesten gcc-Version und Jörgs Muster-Makefile (mit
wenigen Änderungen).

Viele Grüße, Stefan

Antwort schreiben

Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.

Wichtige Regeln - erst lesen, dann posten!

  • Groß- und Kleinschreibung verwenden
  • Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.