SSE a seulement ceci pour byte-> word et word-> dword. (pmaddubsw
(SSSE3) et pmaddwd
(MMX/SSE2), qui multiplient verticalement v1 * v2, puis ajoutent horizontalement les paires voisines.)
Je ne sais pas exactement ce que vous voulez que les sorties soient. Vous avez 8 entiers d'entrée (deux vecteurs de 4) et 2 entiers de sortie (un vecteur de deux). Comme il n'y a pas d'insn qui effectue une addition de vecteurs 32 + 32 -> 64b, regardons simplement comment étendre ou étendre les deux éléments 32b d'un vecteur à 64b. Vous pouvez combiner ceci dans tout ce dont vous avez besoin, mais gardez à l'esprit qu'il n'y a pas de paires additionnelles-horizontales phaddq
, seulement vertical paddq
.
phaddd
est similaire à ce que vous voulez, mais sans l'élargissement: la moitié inférieure du résultat est la somme des paires horizontales dans le premier opérande, la moitié supérieure est la somme des paires horizontales dans le deuxième opérande. Cela vaut à peine la peine d'utiliser si vous avez besoin de tous ces résultats, et vous n'allez pas les combiner davantage. (c'est-à-dire qu'il est généralement plus rapide de mélanger et d'ajouter verticalement au lieu de faire phadd
pour additionner horizontalement un accumulateur de vecteur à la fin d'une réduction.) Si vous voulez tout résumer à un résultat, faites des sommes verticales normales jusqu'à ce que vous tombiez à un registre.) phaddd
pourrait être mis en œuvre dans le matériel pour être aussi rapide que paddd
(latence de cycle unique et le débit), mais il n'est pas dans toute CPU AMD ou Intel.
Comme Mysticial a commenté, SSE4.1 pmovzxdq
/pmovsxdq
sont exactement ce dont vous avez besoin, et peut même le faire à la volée dans le cadre d'une charge à partir d'un emplacement de mémoire 64b (contenant deux entiers 32b).
SSE4.1 a été introduit avec Intel Penryn, 2ème génération Core2 (45nm die shrink core2), la génération avant Nehalem. Retomber sur un chemin de code non-vectoriel sur des processeurs plus anciens que cela pourrait convenir, en fonction de combien vous vous souciez de ne pas être lent sur les processeurs qui sont déjà vieux et lent.
Sans SSE4.1:
zéro extension Unsigned est facile. Comme réponse pmdj, il suffit d'utiliser punpck*
lo et salut pour déballer avec zéro.
Si vos entiers sont signés, vous devrez faire l'extension de signe manuellement.
Il n'y a pas psraq
, seulement psrad
(Dword arithmétique arithmétique à droite) et psraw
. S'il y en avait, vous pourriez déballer avec lui-même et ensuite effectuer un décalage arithmétique de 32b. Au lieu de cela, nous avons probablement besoin de générer un vecteur où chaque élément est transformé en son bit de signe. Mélangez ensuite cela avec un vecteur non compressé (mais pblendw
est SSE4.1 aussi, donc nous devions utiliser por
). Ou mieux, déballez le vecteur original avec un vecteur de signes-masques.
# input in xmm0
movdqa xmm1, xmm0
movdqa xmm2, xmm0
psrad xmm0, 31 ; xmm0 = all-ones or all-zeros depending on sign of input elements. xmm1=orig ; xmm2=orig
; xmm0 = signmask; xmm1=orig ; xmm2=orig
punpckldq xmm1, xmm0 ; xmm1 = sign-extend(lo64(orig))
punpckhdq xmm2, xmm0 ; xmm2 = sign-extend(hi64(orig))
Cela devrait fonctionner avec une latence de 2 cycles pour les deux résultats sur Intel SnB ou IvB. Haswell et plus tard ont seulement un port de shuffle (donc ils ne peuvent pas faire les deux punpck
insns en parallèle), ainsi xmm2 sera retardé pour un autre cycle là. Les processeurs Intel pré-SnB gèlent généralement sur le frontend (décodeurs, etc) avec des instructions vectorielles, car ils font souvent plus de 4B par insn.
Déplacement de l'original au lieu de la copie raccourcit la chaîne de dépendance pour tout produit xmm0
, pour les CPU sans élimination de déplacement (manipulation mov
instructions à l'étape de registre de renommage, ils sont donc sans latence. Intel, et seulement sur IvB et plus tard.) Avec les instructions AVX à 3 opérandes, vous n'avez pas besoin du movdqa
, ou du 3e registre, mais vous pouvez simplement utiliser vpmovsx
pour le low64 de toute façon. Pour vous inscrire étendre le haut 64, vous auriez probablement psrldq
octets déplacer le haut 64 jusqu'à la faible 64.
Ou movhlps
ou punpckhqdq self,self
à utiliser une instruction plus courte à encode. (Ou AVX2 vpmovsx
à un 256b reg, puis vextracti128
128 supérieure, pour obtenir les deux 128b résultats avec seulement deux instructions.)
Contrairement équipes GP-registre (par exemple sar eax, 31
), les changements de vecteur saturent le comte à la place de masquage. Laissant le bit de signe original comme le LSB (décalage de 31) au lieu d'une copie de celui-ci (déplacement de 32) fonctionne bien, aussi. Il a l'avantage de ne pas nécessiter un gros commentaire avec le code expliquant cela pour les personnes qui s'inquiéteraient quand elles verront psrad xmm0, 32
.
[Voici une solution pour 64bit à 128bit pour SSE, SSE + XOP, AVX2, AVX512] (http://stackoverflow.com/questions/27923192/practical-bignum-avx-sse-possible/27978043#27978043) . –
Pourquoi voulez-vous faire cela? Je comprends pourquoi vous voudriez 64b + 64b + carry mais pas 32b + 32b + carry. –