Forum: Compiler & IDEs Optimierung bei Multiplikation


von Stefan (Gast)


Lesenswert?

Hallo!


Ich verwende bei eine Treiber für ein T6963 Display eine Multiplikation 
für das linksschieben

Optimiert wird mit -Os auf einemn ATMega128

Ungefähr so

<code>

i = PowerOf2Tab[7-i];
tmpDaten._int = ((uint8_t)Daten * (uint8_t)i);

<code/>

Wobei tmp_Daten._int eine Union von größe int ist, welches dann je als 
Byte in nem Cache Abgelegt wird und dann zum LCD Geschickt.

i ist PowerOf2 für schieben.

der Gcc optiemiert diesen vorgan auch recht ordentlich, nämlich so.

        andi r24,lo8(7)
  ldi r30,lo8(7)
  ldi r31,hi8(7)
  sub r30,r24
  sbc r31,__zero_reg__
  subi r30,lo8(-(PowerOf2Tab))
  sbci r31,hi8(-(PowerOf2Tab))
  ld r24,Z
  mul r18,r24
  movw r18,r0
  clr r1

Jetzt habe ich das Problem, das ich 2 Multiplikationen der gleichen art 
durchführen muss. Nämlich einmal mit den Daten und einmal mit einer Bit 
Maske für die Breite der Daten


Das sieht dann So aus

        i = PowerOf2Tab[7-i];
  tmpDaten._int = ((uint8_t)Daten * (uint8_t)i);
  tmpMask._int = ((uint8_t)Bits * (uint8_t)i);

Normalerweise würde ich davon ausgehen, das der Gcc nur nochma eine 
Multiplikation durchführt, er macht aber das daraus

        andi r24,lo8(7)
  ldi r30,lo8(7)
  ldi r31,hi8(7)
  sub r30,r24
  sbc r31,__zero_reg__
  subi r30,lo8(-(PowerOf2Tab))
  sbci r31,hi8(-(PowerOf2Tab))
  ld r24,Z
  clr r25
  mov r20,r19
  clr r21
  movw r22,r20
  mul r22,r24
  movw r20,r0
  mul r22,r25
  add r21,r0
  mul r23,r24
  add r21,r0
  clr r1
  clr r19
  movw r22,r18
  mul r22,r24
  movw r18,r0
  mul r22,r25
  add r19,r0
  mul r23,r24
  add r19,r0
  clr r1


Hatt von euch vielleicht jemand eine Idee warum er das macht, und wie 
mann ihm das austreiben könnte ???

Vielen Dank im Vorraus


Stefan

von Uhu U. (uhu)


Lesenswert?

Warum nimmst du nicht den Shiftbefehl << statt einer Multiplikation und 
dem Klimmzug mit PowerOf2Tab[7-i]?

Beispiel:

   int i = 1 << 3;

i hat dann den Wert 8.

von Μαtthias W. (matthias) Benutzerseite


Lesenswert?

Hi

weil die Anzahl der zu shiftenden Stellen erst zur Laufzeit bekannt ist. 
Und das dürfte dann in einer recht ineffizienten ein Bit schiebe 
Schleife resultieren. Mit der Tabellen/Multiplikationsmethode erzwingt 
man eine Multiplikation was auf Controllern mit Hardwaremultiplikator 
und ohne Barrelshifter deutlich effizienter und berechenbarer ist 
(Laufzeit O(1) statt O(n))

Was der GCC da macht ist mir aber auch nicht klar.

Matthias

von Uhu U. (uhu)


Lesenswert?

Wenns ganz schnell gehen soll und 1792 oder 2048 Byte Flash übrig sind, 
kann man das auch mit einem Tabellen-Lookup machen...

von Stefan (Gast)


Lesenswert?

Hallo!

Für mich sieht es ja so aus aals wenn er nicht mehr 8 bit sondern 16 bit 
multiplieziert, also den Typcast vergisst. Warum was so ist ist mir aber 
volkommen schleierhaft.


Gruß Stefan

von Peter S. (psavr)


Lesenswert?

Wie ist Bits definiert?

Wenn es eine Präprozessor-Konstante ist (z.B. #define Bits 0xF0) dann 
behandelt der AVR-GCC diese defaultmässig als 16-Bit int, selbst wenn Du 
die Konstante explizit als 8-Bit Werd castest...

Ist eigentlich schade, dass der AVR-GCC den Typecast für Konstanten 
ignoriert, hier wird sehr viel an Code-Effizienz verschenkt!!!

von Stefan (Gast)


Lesenswert?

Hallo Peter!

Bits ist die Übergebene Maske der Funktion, also keineKonstante

Was mich nur wunder ist halt, das wenn er eine Multiplikation ausführt 
er es schön knapp hält, und bei genau 2 mal das gleiche so aufbläßt.

wenn ich z.b. Diesen machen würde:
1
 i = PowerOf2Tab[7-i];
2
  tmpDaten._int = ((uint8_t)Daten * (uint8_t)i);
3
  tmpMask._int = (uint8_t)(((uint8_t)Bits * (uint8_t)i));

Also eine Multiplikation als voll 8 bit ausführen bläßte er eine zwar 
nicht ganz so auf, aber vergisst bei der anderen ein byte wie es sein 
sollte
ungefährt so:
1
        subi r30,lo8(-(PowerOf2Tab))
2
  sbci r31,hi8(-(PowerOf2Tab))
3
  ld r20,Z
4
  ld r24,X+
5
  ld r25,X
6
  sbiw r26,1
7
  mul r20,r18
8
  movw r18,r0
9
  clr r1
10
  com r18
11
  com r19
12
  mul r20,r21
13
  mov r20,r0
14
  clr r1


Leider kann ich es nicht so machen, das er es knapp und vollständig 
hält.


Jemand vielleicht eine Idee oder Vorschlag???


Gruß Stefan

von Stefan (Gast)


Lesenswert?

Hallo!


Da ich trotz aller versuche es nicht geschafft habe, es im reinen C auf 
eine 8*8 bit multiplikation zu beschränken, habe ichnun mit inline 
Assambler gearbeitet. Damit geht mir zwar die Portierbarkeit verlohren, 
aber es funktioniert wie ich will. Hier das Makro:
1
#define MulByteByte(a,b,c) asm volatile("mul %1,%2"    "\n\t"\
2
                    "movw %A0,__tmp_reg__"  "\n\t"\
3
                    "clr __zero_reg__"    "\n\t"\
4
                    :"=r" (c)    \
5
                    :"r"(a),"r" (b))


und was er mir daraus macht:
1
subi r30,lo8(-(PowerOf2Tab))
2
  sbci r31,hi8(-(PowerOf2Tab))
3
  ld r20,Z
4
  ld r24,X+
5
  ld r25,X
6
  sbiw r26,1
7
/* #APP */
8
  mul r20,r18
9
  movw r18,__tmp_reg__
10
  clr __zero_reg__
11
  
12
/* #NOAPP */
13
  and r25,r18
14
  and r24,r19
15
/* #APP */
16
  mul r20,r21
17
  movw r20,__tmp_reg__
18
  clr __zero_reg__
19
  
20
/* #NOAPP */
21
  or r25,r20
22
  or r24,r21
23
  st X+,r24
24
  st X,r25


Bis Später, 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.