Entwickler-Ecke

Algorithmen, Optimierung und Assembler - XMM-Register auf 0 testen


Motzi - Mo 26.11.07 20:20
Titel: XMM-Register auf 0 testen
Hallo,

weiß wer eine effiziente Möglichkeit zu testen ob ein XMM-Register den Wert 0 enthält? Die Instruktion PTEST, die equivalent zur herkömmlichen TEST Instruktion funktioniert (nur eben für MMX- bzw XMM-Register) gibt es erst ab SSE4. Ich hätte gerne eine möglichst effiziente Methode die mit den Instruktionen bis (inkl.) SSE2 auskommt.

LG, Manuel


OlafSt - Mi 28.11.07 12:44

MMX ist nicht mein Gebiet, aber vielleicht kannst du sowas konstruieren:


Quelltext
1:
2:
or al,al
je IstNull


Motzi - Mi 28.11.07 13:23

Ne, so einfach ist das leider nicht, da die MMX- bzw. SSE-Instruktionen keine Flags setzen - sonst wäre es kein Problem..! ;)


golgol - Mi 28.11.07 13:52

Wenn ich mich recht entsinne konnte doch mit MOVD der Inhalt vom XMM geholt werden. Wieso holst du denn nicht einfach und testest dann das neue Register auf 0? Also:


Quelltext
1:
2:
3:
4:
movd al xmm
movd al 0
or al al
je irgendwohin


Motzi - Mi 28.11.07 14:12

Ein XMM-Register ist 128Bit breit, die normalen Allzweck-Register nur 32-Bit. Momentan mache ich es so, dass ich das XMM-Register 4 mal um 32 nach rechts shifte und das Ergebnis jeweils mit sich selbst OR-verknüpfe. Dann hol ich mir die untersten 32-Bit in ein Allzweck-Register und teste dort auf 0.
Das ist aber nicht sonderlich schön, deswegen wollte ich fragen ob jemand eine andere/effizientere Möglichkeit kennt.

LG, Manuel


Lossy eX - Mi 28.11.07 14:32

Also ich kenne ansonsten nur noch die Compare Befehler von MMX/SSE. Die sind aber eher nur so für den internen Gebrauch bestimmt, da die halt eher zur Seperierung der einzelnener Stellen in den Register dienen.

Aber mal anders gefragt. Was hast du denn mit der Erkenntniss vor bzw was steckt hinter dem Ganzen? Evtl gehts ja noch ganz anders. Bin zwar da nicht so der Crack aber mal schauen. Evtl hilft es ja anderen. ;)


Motzi - Mi 28.11.07 15:11

Ich hab 3 XMM-Registern mit Daten, mit denen ich eine etwas kompliziertere Berechnung durchführe. Wenn alle 3 Register 0 sind, dann kann ich mir die Berechnung aber sparen -> ich verknüpfe alle 3 Register per OR und muss dann nur noch schaun ob das Ergebnis 0 ist. Da stellt sich jetzt eben nur die Frage wie man das effizient durchführt.

Das ganze ist für ein Übungsprojekt für die Uni, wo wir eine gegebene Problemstellung möglichst effizient implementieren sollen - egal welche Sprache, Algorithmen etc. eingesetzt werden. Das Ganze wird mit einem Profiler gemessen und es sollen eben so wenig Zyklen wie nötig brauchen. Wir haben uns bereits ein recht gutes Konzept überlegt das vermutlich sehr effizient ist - nur diese eine Überprüfung ist IMHO noch verbesserungswürdig.

LG, Manuel


Lossy eX - Mi 28.11.07 15:54

Evtl wäre es sogar das Einfachste so etwas direkt in den Allzweckregistern zu lösen. Noch bevor du die Daten in die XMM Register lädst. Denn das Laden und Umformen in den XMM Registern kostet ja auch Zeit. Zu mal der Wert auch wieder in die Allzweckregister muss und du die originalen Werte innerhalb der XMM Registern auch sichern müsstest. So würdest du 4 (oder 12) Mal einen 32 Bit Wert mit OR verknüpfnen und bräuchtest nur diesen zu vergleichen. Der Cache sollte ja sein übriges tun bzw kann man seit SSE den Cache auch selber irgendwie kontrollieren.

Allerdings wie häufig kann denn so etwas passieren, dass alle Register gleichzeitig leer sind? Denn wenn so etwas eher selten der Fall ist lohnt es vielleicht gar nicht. Kann ich aber nicht abschätzen. Vermute aber eher mal, dass du sonst auch gar nicht gefragt hättest. ;)

Evtl würde es auch etwas bringen bei der Abfrage oberhalb bereits nach den ersten 4 DWORDs schon mal zu testen. Je nach Seltenheit der Nullstellen hätte man so einen vorzeitigen Abbruch, da die erste Stelle bereits nicht 0 wäre.


Motzi - Mi 28.11.07 17:37

Naja, ich hab 3 128-Bit Werte, das entspricht 12 32-Bit Werten. Diese in die Allzweck-Register zu laden und dort dann alle miteinander or-verknüpfen und überprüfen erscheint mir auch nicht gerade effizient. Vor allem wenn die Werte ungleich 0 sind, denn dann muss ich sie erst recht nochmal in die XMM-Register laden. Der Cache kann in SSE mit PrefetchX "kontrolliert" werden, was wir auch tun werden.

Es kann u.U. durchaus öfters vorkommen, dass die Werte 0 sind. Wenn das nicht der Fall wäre würde ich die Überprüfung gar nicht einbauen, da mir sonst schon die branch misspredictions die Performance versauen könnten.


Lossy eX - Mi 28.11.07 19:47

Das stimmt natürlich. So wirklich optimal ist das nicht. Wie gesagt könnte man evtl die Überprüfung frühzeitig abbrechen. Was aber im Falle von vielen Nullen zu übermäßigem Overhead führt.

Müsste man evtl. mal testen was davon mehr bringt. Aber ich vermute fast, dass es langsamer sein würde als wie wenn man direkt mit den XMM Registern arbeitet. Sonst wüsste ich auch nicht was man noch machen könnte. Bin aber auch nicht so extrem bewandert was so was angeht. ;)


OlafSt - Do 29.11.07 14:18

Vielleicht helfen die Instruktionen PCMPEQB/PCMPEQW/PCMPEQD ein Stück weiter. Sie vergleichen ein XMM/SIMD-Register mit einem anderen XMM/SIMD-Register bzw. einer 64/128-Bit Memory location.

Sind die Werte gleich, werden in DEST alle Bits gelöscht. Wenn nicht, werden in DEST alle Bits gesetzt. Es gilt dann nur noch, herauszufinden, ob alle Bits gelöscht sind.


Motzi - Do 29.11.07 14:22

user profile iconOlafSt hat folgendes geschrieben:
[..] Es gilt dann nur noch, herauszufinden, ob alle Bits gelöscht sind.

Was dann auf dasselbe hinausläuft wie das XMM-Register auf 0 zu testen... ;)


OlafSt - Di 04.12.07 15:40

Durch Zufall drüber gestolpert...

Zitat:
comiss and ucomiss compare the single precision values and set the ZF, PF and CF flags to show the result. The destination operand must be a SSE register, the source operand can be a 32-bit memory location or SSE register.


Vielleicht ist das nützlich...