Forum: Compiler & IDEs Optimierung mittels typecast


von Malte Marwedel (Gast)


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?

von Thorsten (Gast)


Lesenswert?

Ist (uint_8t) = (unsigned char) ?

von Malte Marwedel (Gast)


Angehängte Dateien:

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

von Matthias (Gast)


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

von Malte Marwedel (Gast)


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.

von Matthias (Gast)


Lesenswert?

Hi

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

Matthias

von Peter D. (peda)


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

von Malte Marwedel (Gast)


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.

von Harry (Gast)


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

von Stefan Kleinwort (Gast)


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

von Fritz Ganter (Gast)


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  ****   }

von Malte Marwedel (Gast)


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) {

von Stefan Kleinwort (Gast)


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

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.