Mit '-Os' produziert der avr-g++ (sowohl 7.2 also auch 8.0) brav die
optimale Variante:
1
merge1(unsignedchar&,unsignedcharconst&):
2
movwr30,r24;dst,dst
3
movwr26,r22;,src
4
ldr24,X;*src_10(D),*src_10(D)
5
ldr25,Z;*dst_11(D),*dst_11(D)
6
bstr24,0;*src_10(D)
7
bldr25,0;tmp56
8
stZ,r25;*dst_11(D),tmp56
9
ret
10
merge2(unsignedchar&,unsignedcharconst&):
11
movwr30,r24;dst,dst
12
ldr25,Z;_1,*dst_10(D)
13
movwr26,r22;,src
14
ldr24,X;*src_11(D),*src_11(D)
15
bstr24,0;*src_11(D)
16
bldr25,0;tmp55
17
stZ,r25;*dst_10(D),tmp55
18
ret
bestehend aus bst/bld.
Ändert man allerdings das zu kopierende Bit (s.a. comment oben), so
erkennt der gcc diese Optimierungsmöglichkeit nicht mehr und es
entsteht:
1
merge1(unsignedchar&,unsignedcharconst&):
2
movwr30,r24;dst,dst
3
movwr26,r22;,src
4
ldr25,X;*src_10(D),*src_10(D)
5
andir25,lo8(2);tmp52,
6
ldr18,Z;*dst_11(D),*dst_11(D)
7
andir18,lo8(-3);tmp54,
8
orr25,r18;tmp56,tmp54
9
stZ,r25;*dst_11(D),tmp56
10
ret
11
merge2(unsignedchar&,unsignedcharconst&):
12
movwr30,r24;dst,dst
13
ldr24,Z;_1,*dst_10(D)
14
movwr26,r22;,src
15
ldr25,X;*src_11(D),*src_11(D)
16
eorr25,r24;tmp52,_1
17
andir25,lo8(2);tmp54,
18
eorr25,r24;tmp55,_1
19
stZ,r25;*dst_10(D),tmp55
20
ret
Rein aus Interesse: wenn der Optimierer im gcc diese Möglichkeit für
Bit0 erkennt, sollte er das m.E. ja auch für Bit 1...7 erkennen können?
Ist das einfach ein Bug im Optimizer (korrekt ist der Code ja) oder gibt
es andere Gründe, die dagegen sprechen.
Dasselbe gilt übrigens auch wenn der DT nicht uint8_t ist. Dann wird
diese optimale Variante bst/bld gar nicht generiert (auch nicht für
Bit0).
Vielleicht kann jemand der Mitglieder, die auch im gcc-Projekt aktiv
sind, mich ein wenig "erhellen" ... Danke!
@Wilhelm M. (wimalopaan)
>Das könnte eine Lösung sein, doch geht es mehr darum zu verstehen, warum>das so wie oben beschrieben ist.
Warum? Willst du die Innereien des Compilers verstehen?
Falk B. schrieb:> @Wilhelm M. (wimalopaan)>>>Das könnte eine Lösung sein, doch geht es mehr darum zu verstehen, warum>>das so wie oben beschrieben ist.>> Warum? Willst du die Innereien des Compilers verstehen?
Ja, genau (s.o.)
Wilhelm M. schrieb:> doch geht es mehr darum zu verstehen, warum> das so wie oben beschrieben ist.
GCC ist Open Source, mit reichlich Optionen für die Darstellung der
Zwischenstufen bei der Optimierung. Und wenn jener Forenteilnehmer mit
recht viel Einblick in BLD/BST Optimierungen derzeit nicht mitliest,
müsstest du dir eben die Mühe machen, selber reinzuschauen.
Wilhelm M. schrieb:>> Warum? Willst du die Innereien des Compilers verstehen?>> Ja, genau (s.o.)
Verstehen - oder verstehen lassen, mit detaillierter Erklärung? ;-)
A. K. schrieb:> Wilhelm M. schrieb:>> doch geht es mehr darum zu verstehen, warum>> das so wie oben beschrieben ist.>> GCC ist Open Source, mit reichlich Optionen für die Darstellung der> Zwischenstufen bei der Optimierung. Und wenn jener Forenteilnehmer mit> recht viel Einblick in BLD/BST Optimierungen derzeit nicht mitliest,> müsstest du dir eben die Mühe machen, selber reinzuschauen.
Werde ich tun.
Es hätte aber auch sein können, dass der geballte Sachverstand in diesem
Forum sagt, dass das, was ich da oben vermute, ist Quatsch, weil ...
A. K. schrieb:> Wilhelm M. schrieb:>> doch geht es mehr darum zu verstehen, warum>> das so wie oben beschrieben ist.>> GCC ist Open Source, mit reichlich Optionen für die Darstellung der> Zwischenstufen bei der Optimierung. Und wenn jener Forenteilnehmer mit> recht viel Einblick in BLD/BST Optimierungen derzeit nicht mitliest,> müsstest du dir eben die Mühe machen, selber reinzuschauen.>> Wilhelm M. schrieb:>>> Warum? Willst du die Innereien des Compilers verstehen?>>>> Ja, genau (s.o.)>> Verstehen - oder verstehen lassen, mit detaillierter Erklärung? ;-)
Ich weiß nicht, was das jetzt wieder soll: dieses Forum ist doch nicht
nur dazu da, Fragen zu stellen, sondern auch Antworten zu bekommen,
oder? Und wer die Frage dumm findet oder einfach keine Antwort geben
will, der braucht auch keinen Beitrag zu schreiben.
Ich finde die Frage nicht dumm, aber ich verstehe, daß da keiner große
Lust dazu hat. Ob nun 10 oder 11 Zyklen ist nicht so der riesen
Unterschied.
Davon abgesehen ist mir in der Praxis bisher keine auch nur ähnliche
Aufgabe begegnet. Ich mag viel lieber Aufgaben, die auch einen
praktischen Bezug haben.
Selbst zu Assemblerzeiten kann ich mich nicht erinnern, bst/bld je
benötigt zu haben.
Ich habe T nur als Userflag benutzt, z.B. um zu unterscheiden, ob die
Division den Quotienten oder den Rest berechnen soll.
Beim 8051 waren die Bitbefehle erheblich leistungsfähiger, da konnte man
sogar Bits aus Portpins einlesen oder ausgeben (MOV C, P1.2 oder MOV
P2.3, C).
Peter D. schrieb:> Selbst zu Assemblerzeiten kann ich mich nicht erinnern, bst/bld je> benötigt zu haben.
Schau dir man die Beispiele zu __builtin_avr_insert_bits an. Du wusstest
bisher bloss noch nicht, dass du das brauchst. ;-)
Geht natürlich alles auch anders. Nur langsamer oder platzraubender.
Wilhelm M. schrieb:> doch geht es mehr darum zu verstehen, warum> das so wie oben beschrieben ist.
-fdump-tree-all -fdump-rtl-all -fdump-ipa-all
und: lesen :o)
> void merge1(value_type& dst, const value_type& src)
Wohl ein C++er-Reflex das &src. Wenn das Zeug nicht geinlint wird
erzwingt das einen 16-Bit Zeiger (AVR) und indirekten Zugriff. Wenn es
dir um "optimal" geht, dann solltest du das beheben bevor du über
Feinheiten der GCC-Optimizer sinnierst.
Johann L. schrieb:> Wohl ein C++er-Reflex das &src. Wenn das Zeug nicht geinlint wird> erzwingt das einen 16-Bit Zeiger (AVR) und indirekten Zugriff.
Das stimmt nicht ganz, da es ein const T& ist, und dort normalerweise
die ipa sra Optimierung gemacht wird (bei einem template, woher der Code
auch stammt).
> Wenn es> dir um "optimal" geht, dann solltest du das beheben bevor du über> Feinheiten der GCC-Optimizer sinnierst.
Das spielt für die angesprochene Binnenoptimierung aber keine Rolle.
A. K. schrieb:> Geht natürlich alles auch anders. Nur langsamer oder platzraubender.
Man sollte eher sagen, minimal langsamer und größer.
Bei völligem Durcheinander (8 * bst/bld) braucht das klassische SBRC+ORI
gerademal initial ein CLR bzw. ANDI mehr, also 18 statt 17
Zyklen/Befehle.
Die Einsparung ist also winzige 5%.
Wilhelm M. schrieb:> Das spielt für die angesprochene Binnenoptimierung aber keine Rolle.
Dann bleibt dir ein Blick in die verwendeten Pattern nicht erspart.
Siehe entsprechende -fdump-*-all optionen von oben.