2015-11-12 5 views
6

Ich suche einen SSE-Befehl, der zwei Argumente von vier 32-Bit-Ganzzahlen in __m128i, berechnet die Summe der entsprechenden Paare und gibt das Ergebnis als zwei 64-Bit-Ganzzahlen in __m128i zurück.SSE-Befehl zum Summieren von 32-Bit-Ganzzahlen zu 64-Bit

Gibt es eine Anleitung dazu?

+0

[Hier ist eine Lösung für 64bit zu 128bit für SSE, SSE + XOP, AVX2, AVX512] (http://stackoverflow.com/questions/27923192/practical-bignum-avx-sse-possible/27978043#27978043) . –

+0

Warum möchten Sie das tun? Ich verstehe, warum Sie möchten 64b + 64b + tragen, aber nicht 32b + 32b + tragen. –

Antwort

6

Es gibt keine SSE-Operationen mit Übertrag. Dazu müssen Sie zuerst die 32-Bit-Ganzzahlen (punpckldq/punpckhdq) in 4 Gruppen von 64-Bit-Ganzzahlen entpacken, indem Sie einen Helfer-Vektor mit nur Nullen verwenden und dann eine 64-Bit-Addition verwenden.

+3

SSE4.1 hat einige Integer-Erweiterungsbefehle, die dies etwas einfacher und schneller machen. – Mysticial

+1

@Mysticial: Für vorzeichenbehaftete Ganzzahlen ist es tatsächlich eine * Menge * einfacher und schneller mit 'pmovsx'. Es ist nicht so groß, wie ich zuerst dachte, da ich eine ziemlich gute Idee hatte, während ich meine Antwort für das Entpacken mit einer Zeichenmaske schrieb, anstatt zu entpacken und * dann * eine Zeichenmaske zu mischen. Aber 'pmovsx' ist sehr nett, wenn Sie aus dem Speicher laden, ansonsten müssen Sie arbeiten, um die obere Hälfte zur Vorbereitung auf Vorzeichen zu verschieben. –

2

SSE hat nur dies für byte-> Wort und Wort-> dword. (pmaddubsw (SSSE3) und pmaddwd (MMX/SSE2), die vertikal v1 * v2 multiplizieren, dann horizontal benachbarte Paare hinzufügen.)

Ich bin mir nicht klar, was Sie wollen, dass die Ausgänge zu sein. Sie haben 8 ganze Zahlen (zwei Vektoren von 4) und 2 ganze Zahlen (ein Vektor von zwei). Da es keinen insn gibt, der irgendeine Art von 32 + 32 -> 64b-Vektoraddition ausführt, schauen wir uns einfach an, wie man die niedrigen zwei 32b-Elemente eines Vektors auf 64b null-extendieren oder vorzeichenerweitern lässt. Sie können dies kombinieren, was auch immer Sie brauchen, aber denken Sie daran, es gibt keine add-horizontal-Paare phaddq, nur vertikal paddq.

phaddd ist ähnlich wie Sie wollen, aber ohne die Erweiterung: niedrige Hälfte des Ergebnisses ist die Summe der horizontalen Paare im ersten Operanden, hohe Hälfte ist die Summe der horizontalen Paare im zweiten Operanden. Es lohnt sich nur, wenn Sie all diese Ergebnisse benötigen, und Sie werden sie nicht weiter kombinieren. (Dh es ist normalerweise schneller zu shuffle und vertikal add anstatt phadd zu laufen, um einen Vektorakkumulator am Ende einer Reduktion horizontal zu summieren. Und wenn Sie alles zu einem Ergebnis summieren, machen Sie normale vertikale Summen, bis Sie unten sind zu einem Register.) phadddkönnte in Hardware implementiert werden, um so schnell wie paddd (Single-Zyklus-Latenz und Durchsatz), aber es ist nicht in jedem AMD oder Intel-CPU.


Wie Mysticial kommentierte SSE4.1- pmovzxdq/pmovsxdq sind genau das, was Sie brauchen, und kann es sogar im laufenden Betrieb als Teil einer Last von einer 64b Speicherplatz (mit zwei 32b ganzen Zahlen).

SSE4.1 wurde mit Intel Penryn, 2. Generation Core2 (45nm die Shrink Core2), die Generation vor Nehalem eingeführt. Das Zurückfallen auf einen Nicht-Vektor-Code-Pfad auf CPUs, die älter sind als das, kann in Ordnung sein, abhängig davon, wie viel Sie daran interessiert sind, nicht auf CPUs zu verlangsamen, die bereits alt und langsam sind.


Ohne SSE4.1-:

Unsigned Null-Erweiterung ist einfach. Wie pmdj antwortete, benutze einfach punpck* lo und hi mit Null zu entpacken.

Wenn Ihre Ganzzahlen signiert sind, müssen Sie die Zeichenerweiterung manuell durchführen.

Es gibt keine psraq, nur psrad (Packed Shift Right Arithmetic Dword) und psraw. Wenn es so wäre, könntest du mit sich selbst auspacken und dann arithmetisch nach rechts verschieben um 32b.

Stattdessen müssen wir wahrscheinlich einen Vektor generieren, bei dem jedes Element in sein Vorzeichenbit umgewandelt wird. Dann mische das mit einem entpackten Vektor (aber pblendw ist SSE4.1, also müssten wir por verwenden).

Oder besser, entpacken Sie den ursprünglichen Vektor mit einem Vektor von Zeichenmasken.

Dies sollte mit 2 Zyklus Latenz für beide Ergebnisse auf Intel SnB oder IvB ausgeführt werden. Haswell und später haben nur einen Shuffle-Port (also können sie nicht beide punpck inss parallel tun), so dass xmm2 dort für einen weiteren Zyklus verzögert wird. Pre-SnB Intel CPUs sind meist Engpässe am Frontend (Decoder, etc) mit Vektorinstruktionen, da sie oft mehr als 4B pro Inch betragen.

das Original statt der Kopie Shifting verkürzt die Abhängigkeitskette für was auch immer xmm0, für CPUs ohne Bewegung Eliminierung erzeugt (mov Anweisungen auf dem Register-umbenennen Bühne Handhabung, so sind sie ohne Latenz. Intel-only, und nur IvB und später.) Mit 3-Operanden AVX-Anweisungen, würden Sie nicht die movdqa, oder das 3. Register, aber dann könnten Sie einfach vpmovsx für die Low64 sowieso verwenden. Um Vorzeichen erweitern die hohe 64, dann würden Sie wahrscheinlich psrldq Byte-Verschiebung die hohe 64 bis in den unteren 64

Oder movhlps oder punpckhqdq self,self zu verwenden kürzerer zu kodieren Anweisung. (Oder AVX2 vpmovsx zu einem 256b reg, und dann vextracti128 die oberen 128, mit nur zwei Anweisungen beiden 128b Ergebnisse zu erhalten.)


Im Gegensatz zu Verschiebungen GP-Register (zB sar eax, 31), Vektorverschiebungen sättigen die Zählung statt der Maskierung. Das Original-Zeichen-Bit als das LSB (Verschieben um 31) anstelle einer Kopie davon (Verschieben um 32) zu lassen, funktioniert ebenfalls gut. Es hat den Vorteil, dass es keinen großen Kommentar in dem Code erfordert, der dies für Leute erklärt, die sich sorgen würden, wenn sie psrad xmm0, 32 sehen würden.