Nicht angemeldet. · Kennwort vergessen · Registrieren

morty
SPiC-Meister
(Moderator)
Mitglied seit 05/2011
331 Beiträge
Betreff: Fragestunde integer propagation
Nachdem ich heute etwas falsches behauptet habe, hier die Erklärung dazu:
Ja, es wird wirklich mit int gerechnet. Aber - und hierher kam mein Denkfehler - dies ist der Fall ohne Optimierung. Wenn ich folgendes habe:
  1. uint8_t a = (uint8_t) b + (uint8_t) c;
Wird alles oberhalb des 8ten Bits eh weggeworfen, da a ja nur 8 Bit aufnehmen kann. In sofern, optimiert der Compiler auf 8 Bit. Dies ist auch der Fall, wenn b und c 16 Bit sind, weil die oberen 8 Bit ja keinen Einfluss auf das Ergebnis haben. Bei der Multiplikation ist das natürlich nicht mehr möglich.

Bei dem Beispiel aus der Klausur:
  1. a + a * 2  - 50
Macht der avr-gcc _mit Optimierung_ folgends:
 * a * 3 mit 16 Bit. An dieser Stelle ist recht interessant, dass der Compiler (in dem Fall der recht betagte 4.3.5) aus a + a + a deutlich besseren Code generiert als aus a + a * 2. Im Fall a + a + a sind es nämlich 3 8-Bit-Additionen, was _sehr_ viel schneller ist, als jegliche Multiplikation.
 * <erg> - 50.


In sofern wäre die Richtige Antwort: Ohne Optimierung findet kein over- oder underrun statt; es kann aber sein, dass der Compiler entsprechende Optimierungen vornimmt, dass dies trotzdem passiert.
morty
SPiC-Meister
(Moderator)
Mitglied seit 05/2011
331 Beiträge
So, hab mit jetzt den ganz aktuellen 4.8er avr-gcc übersetzt, und bei dem sieht das so aus:

uint8_t test01(uint8_t v1){
    uint8_t rv;
    rv = (v1 + v1 + v1 - 50);
   e:    98 2f           mov    r25, r24
  10:    99 0f           add    r25, r25
  12:    92 53           subi    r25, 0x32    ; 50
    return rv;
}
  14:    89 0f           add    r24, r25
  16:    08 95           ret

Zur Erklärung (falls das verwirrend ist, einfach ignorieren!): Auf dem AVR werden die ersten beiden Parameter über die register 24,25 und 22,25 übergeben. Der Rückgabewert kommt (im Normalfall) in die Register 24,25 geschrieben. Hier ist es Aufgabe der aufrufenden Funktion die verwendeten Registerpaare zu sichern. Daher muss dir Funktion hier das R25 nicht sichern.

mov  r25, r24         -> Kopiere r24, in dem der Wert v1 seht in r25
add  r25, r25         -> Addiere r25 zu r25 (v1 + v1)
subi r25, 0x32 ; 50   -> Ziehe 0x32 bzw 50 von r25 ab ( v1 + v1 - 50)
add  r24, r25         -> Addiere r24 zu r25 (v1 + v1 -50 + v1). Jetzt steht auch der Richtige wert in r25 dem Rückgaberegister.
                         Da es ein uint8_t ist, kann r25 einen beliebigen wert haben (muss aber wie gesagt von der aufrufenden
                         Funktion trotzdem gesichert werden).
ret                   -> Springe zurück.
Warum er am Ende erst subtrahiert und dann addiert ist mir nicht ganz klar, kommt aber auf das Gleiche raus.
morty
SPiC-Meister
(Moderator)
Mitglied seit 05/2011
331 Beiträge
Mist, hab die falsche Funktion kopiert. Die Version mit der Multiplikation ist immernoch einen Tick schlechter - aber immernoch besser:
uint8_t test0(uint8_t v1){
    uint8_t rv;
    rv = (v1 + v1 * 2 - 50);
   0:    98 2f           mov    r25, r24
   2:    99 0f           add    r25, r25
   4:    98 0f           add    r25, r24
    return rv;
}
   6:    89 2f           mov    r24, r25
   8:    82 53           subi    r24, 0x32    ; 50
   a:    08 95           ret
Schließen Kleiner – Größer + Auf diesen Beitrag antworten:
Prüfcode: VeriCode Gib bitte das Wort aus dem Bild ins folgende Textfeld ein. (Nur die Buchstaben eingeben, Kleinschreibung ist in Ordnung.)
Smileys: :-) ;-) :-D :-p :blush: :cool: :rolleyes: :huh: :-/ <_< :-( :'( :#: :scared: 8-( :nuts: :-O :troll:
Weitere Zeichen:
Gehe zu Forum
Powered by the Unclassified NewsBoard software, 20110527-dev, © 2003-8 by Yves Goergen