Hallo an alle,
Ich benutz das WinAvr 20070525 Packet mit dem GCC 4.1.2. Optimierung: s
Ich hab eine Funktion geschrieben. Sie ist zwar noch nicht fertig, aber
egal.
Kannst du bitte erst einmal erklären, was denn genau dein Problem
ist?
Am besten immer mit compilierfähigem Code belegen, damit man das
nachvollziehen kann.
Das Stückchen Disassembler-Listing da verwirrt eher, als dass es
mir irgendwie hilft zu verstehen, was du hier eigentlich erwartest
und was dann nicht in Erfüllung gegangen ist.
Btw., / und % sind beides Divisionen und damit teure Operationen.
Da eine Division immer auch den Rest gleichzeitig mit berechnet,
kann man das durch die Funktion div() in einem Schritt erledigen --
spart einen Aufruf der Divisionsfunktion.
Lass doch mal den Disassembler-Krempel weg, und guck dir an, was der
Compiler für diese Funktion als Assemblercode generiert (Kommando
"make sht1c.s", wobei ich es ohne -gstabs laufen lassen habe, damit es
übersichtlicher wird).
1
.global sht_raw_to_physical
2
.type sht_raw_to_physical, @function
3
sht_raw_to_physical:
4
/* prologue: frame size=0 */
5
/* prologue end (size=0) */
6
movw r30,r24
7
ld r24,Z
8
ldd r25,Z+1
9
subi r24,lo8(-(-4000))
10
sbci r25,hi8(-(-4000))
11
std Z+1,r25
12
st Z,r24
13
ldi r22,lo8(100)
14
ldi r23,hi8(100)
15
rcall __udivmodhi4
16
st Z,r24
17
/* epilogue: frame size=0 */
18
ret
In der ersten Zeile wird der Z-Pointer mit dem ersten Argument (temp)
geladen. In der zweiten bis siegenten Zeile wird temp->_int gelesen,
4000 subtrahiert, und zurückgespeichert. Das Ergebnis steht gleich
als erstes Argument für die interne Funktion __udivmodhi4 in den
richtigen Registern, es muss danach nur noch der Dividend 100 in
Register r22/r23 geladen werden, danach kann die Division aufgerufen
werden. Das Ergebnis wird dann nach temp->komma abgespeichert.
Nun verwundert natürlich auf den ersten Blick, was er hier mit
temp->komma macht, nicht wahr? Das verwundert nicht mehr, wenn man in
den Code reinguckt, wie sht_val definiert ist. Das ist nämlich eine
union, d. h. die Elemente "ganz" und "komma" belegen den gleichen
Speicherplatz! Der Compiler erkennt also richtig, dass er den Wert
von "ganz" gar nicht erst abspeichern muss, da der danach sowieso
durch "komma" überschrieben wird. Das ist vermutlich nicht ganz das,
was du wolltest...
Der Compiler hätte übrigens noch etwas besser optimieren können: die
Zuweisung von r24 nach Z vor dem Aufruf der Division ist unnötig,
da dieses Byte danach ja wieder zerstört wird. Das hätte er ggf.
herausfinden können, indem man "temp" mit dem Schlüsselwort
"restrict" gekennzeichnet hätte (C99-Feature); macht er aber selbst
dann nicht, weil er die Zuweisung der beiden Bytes einer 16-Bit-Zahl
nicht trennen kann und die Zuweisung von r25 nach Z+1 nicht
redundant ist.
Die lokale Variable test wird gar nicht erst berechnet, da der
Optimierer feststellt, dass die Berechnung komplett für die Katz' wäre
-- sie wird ja nirgends benutzt.
Ok, danke. Jetzt is alles klar :) Verwende ich test, Kommt auch die
Berechnung rein.
Ich hab noch eine Frage. Ich hab da ja eigentlich sehr koplizierte
Rechnung. Ich hab das auf Integer erweitert und dann die Division.
Kann ich da noch was für den Avr optimieren?
>Kann ich da noch was für den Avr optimieren?
Ja. Deine Denk- und Ausdrucksweise! Die beste Opimierungsmöglichkeit
ist, das jemandem zu überlassen, der es kann.
> Kann ich da noch was für den Avr optimieren?
Naja, du arbeitest (in deiner nachfolgenden Rechnung) implizit mit
32-bit-Integern, die sind ziemlich langwierig, da sie in der
Bibliothek wenig optimiert sind.
Andererseits ist es ja immer eine Frage, ob die erreichte Performance
letztlich deinen Anwendungszweck erfüllt. Die AVRs sind ja nicht
gerade extrem langsam.