uint8_t b = 123; uint8_t a = 123; uint16_t result = 0; int main(void) { result = a * b; return result; } ----- -Os / -O2 ----------- lds r24,b ; b, b lds r18,a ; a, a mul r24,r18 ; b, a movw r24,r0 ; D.1915 clr r1 sts (result)+1,r25 ; result, D.1915 sts result,r24 ; result, D.1915 /* epilogue: frame size=0 */ ret ---------------- in dem Fall ist es zufällig(?) wie gewünscht. 15129 kommt raus. (Wenn auch miserabel optimiert trotz -Os / -O2). Gibt es eine Garantie daß das High-Byte nicht verloren geht. Eigentlich sollte man ja erwarten daß "a * b" wieder ein uint8_t ist... Denn bei 16bit x 16bit -> 32bit : uint16_t b = 1234; uint16_t a = 1234; uint32_t result = 0; int main(void) { result = a * b; return result; } ----- -Os ----------- lds r18,b ; b, b lds r19,(b)+1 ; b, b lds r24,a ; a, a lds r25,(a)+1 ; a, a movw r20,r24 ; , a mul r18,r20 ; b, movw r24,r0 ; tmp43 mul r18,r21 ; b, add r25,r0 ; tmp43 mul r19,r20 ; b, add r25,r0 ; tmp43 clr r1 ldi r26,lo8(0) ; D.1914, ldi r27,hi8(0) ; D.1914, sts result,r24 ; result, D.1914 sts (result)+1,r25 ; result, D.1914 sts (result)+2,r26 ; result, D.1914 sts (result)+3,r27 ; result, D.1914 /* epilogue: frame size=0 */ ret ---------------- ... kommt 15428 raus. er schneidet auf 16bit ab !? wiewaswarum kann man das erklären und kontrollieren? Grüße
kxr schrieb: > Eigentlich > sollte man ja erwarten daß "a * b" wieder ein uint8_t ist... Nur wenn man C nicht kennt. Rechnungen unterhalb "int" gibts nicht, jedenfalls nicht dem Ergebnis nach.
kxr schrieb: > wiewaswarum kann man das erklären und kontrollieren? Merkregel: Bei a = b <op> c; hängt der Typ von (b <op> c), also die Bitbreite der Rechnung, nicht vom Typ von a ab, sondern nur von den Typen von b und c. Mit der "nie kleiner als int" Regel obendrauf.
kxr schrieb: > (Wenn auch miserabel optimiert trotz -Os / -O2). Das Registerpaar R0:R1 ist im Registermodell des Compilers eigentlich nicht nutzbar (R1 steht fest als Wert 0), so dass es als über die Multiplikation hinaus erhalten bleibendes Ergebnis nicht in Frage kommt und sofort freigeräumt werden muss. Unter diesem Blickwinkel ist der Code optimal.
A. K. schrieb: > kxr schrieb: > >> wiewaswarum kann man das erklären und kontrollieren? > > Merkregel: Bei > a = b <op> c; > hängt der Typ von (b <op> c), also die Bitbreite der Rechnung, nicht vom > Typ von a ab, sondern nur von den Typen von b und c. Mit der "nie > kleiner als int" Regel obendrauf. tja die "nie kleiner als int" Regel ists dann wohl. sehe bei -mint8 wird das high-byte tatsächlich auch bei 8x8->16 verworfen! Ralf G. schrieb: > Result wird in seiner 32Bit-Größe nie verwendet. macht nix. result ist ja global gespeichert. bei "return 0;" ändert sich nix am casus. PS: A. K. schrieb: >> (Wenn auch miserabel optimiert trotz -Os / -O2). > > Das Registerpaar R0:R1 ist im Registermodell des Compilers eigentlich > nicht nutzbar (R1 steht fest als Wert 0), so dass es als über die > Multiplikation hinaus erhalten bleibendes Ergebnis nicht in Frage kommt > und sofort freigeräumt werden muss. Unter diesem Blickwinkel ist der > Code optimal. auch bei "return 0;" und überall in meinen Programmen macht er (-Os) immer und überall borniert den unnötigen "mov(w) r24,r0" nach dem MUL, nur um das wieder woanders wegzuspeichern. er könnte direkt sts aus r0(:r1) machen.
kxr schrieb: > sehe bei -mint8 wird das high-byte tatsächlich auch bei 8x8->16 > verworfen! stellt sich die Frage wie man allgemein effizient die extended mul-Ergebnisse in C abgreifen kann (ohne vor MUL höher zu casten und "ldi xx,0"en und teurere mul-Routinen auszulösen.
kxr schrieb: >> "nie kleiner als int" Regel > > wo steht eigentlich diese Regel? Irgendwo im C-Standard. Imho passt das hier: > A6.1 Integral Promotion > A character, a short integer, or an integer bit-field, all either signed > or not, or an object of enumeration type, may be used in an expression > wherever an integer may be used. If an int can represent all the values > of the original type, then the value is converted to int; otherwise the > value is converted to unsigned int. This process is called integral promotion. K&R 2nd ed. p.197 S. auch nächste Seite A6.5 Arithmetic Conversions > [...] Otherwise, both operands habe type int.
kxr schrieb: > nur um das wieder woanders wegzuspeichern. er könnte direkt sts aus > r0(:r1) machen. Deine Operation result = a * b; stellt sich für den Compiler ungefähr so dar: Ra = a; Rb = b; Rc = Ra * Rb; result = Rc; Wenn man R1 nicht über die Grenze einer solchen Teiloperation retten kann, weil dafür eben R1=0 gilt, dann klappt das mit der Optimierung so einfach nicht. Zwar liessen sich Rc = Ra * Rb; result = Rc; auch zusammenziehen, aber das hätte im Compiler jemand explizit finden und mit einer eigenen Codesequenz versehen müssen. Das fand wohl niemand lohnend. Nachvollziehbar - der eine MOVW reisst die Latte normalerweise nicht.
kxr schrieb: > kxr schrieb: >> sehe bei -mint8 wird das high-byte tatsächlich auch bei 8x8->16 >> verworfen! > > stellt sich die Frage wie man allgemein effizient die extended > mul-Ergebnisse in C abgreifen kann > (ohne vor MUL höher zu casten und "ldi xx,0"en und teurere mul-Routinen > auszulösen. wie kann ich im Preprocessor den size von int am besten diskrimieren? #if (sizeof(int) < sizeof(uint16_t) #warning "mint8mul" ... #else ... #endif gibt Fehler, sizeof versteht wohl nur der Compiler.
kxr schrieb: > wie kann ich im Preprocessor den size von int am besten diskrimieren? An deiner Stelle würde ich mint8 gar nicht verwenden. Der Schalter ist problematisch und wird von neuesten GCC-Versionen gar nicht mehr unterstützt. Wenn du eine bestimmte Operation auf 8 Bit begrenzen willst, würde ich einen Cast verwenden, z.B. im obigen Fall:
1 | result = (uint8_t)(a * b); |
kxr schrieb: > stellt sich die Frage wie man allgemein effizient die extended > mul-Ergebnisse in C abgreifen kann Auf avr-gcc 4.7 warten.
Ich hatte zu dem Thema Multiplikation mit verschiedenen Datentypen mal hier Beitrag "GCC Inline Assembler Multiplikationen" ein paar Makros gepostet. Gruß Dirk
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.