2015-11-12 20 views
6

Sto cercando un'istruzione SSE che accetta due argomenti di quattro numeri interi a 32 bit in __m128i, calcola la somma delle coppie corrispondenti e restituisce il risultato come due interi a 64 bit in __m128i.Istruzione SSE per sommare interi 32 bit a 64 bit

C'è un'istruzione per questo?

+0

[Ecco una soluzione per 64 bit a 128 bit per SSE, SSE + XOP, AVX2, AVX512] (http://stackoverflow.com/questions/27923192/practical-bignum-avx-sse-possible/27978043#27978043) . –

+0

Perché vuoi farlo? Capisco perché vorrai 64b + 64b + carry ma non 32b + 32b + carry. –

risposta

6

Non ci sono operazioni SSE con carry. Il modo per eseguire questa operazione consiste nel primo decomprimere i numeri interi a 32 bit (punpckldq/punpckhdq) in 4 gruppi di numeri interi a 64 bit utilizzando un vettore di helper tutto-zero e quindi utilizzare l'aggiunta pairwise a 64 bit.

+3

SSE4.1 ha alcune istruzioni per l'ampliamento di interi che lo rendono leggermente più semplice e veloce. – Mysticial

+1

@Mysticial: per interi con segno, in realtà è un * lotto * più facile e veloce con 'pmovsx'. Non è così grande come pensavo all'inizio, dato che ho avuto una buona idea mentre scrivevo la mia risposta per disfare i bagagli con una maschera di segno, invece di disimballare e * poi * mescolare una maschera segno. Ma 'pmovsx' è molto bello se stai caricando dalla memoria, altrimenti devi lavorare per spostare la metà superiore verso la preparazione per la firma, estendendola. –

2

SSE ha solo questo per byte-> word e word-> dword. (pmaddubsw (SSSE3) e pmaddwd (MMX/SSE2), che si moltiplicano in verticale v1 * v2, poi in orizzontale aggiungere coppie confinanti.)

Io non sono chiare su ciò che si desidera che i risultati siano. Hai 8 interi di input (due vettori di 4) e 2 interi di output (un vettore di due). Dal momento che non c'è insn che faccia alcun tipo di aggiunta di 32 + 32 -> 64b vector, vediamo solo come estendere o sign-estendere i due elementi bassi 32b di un vettore a 64b. Puoi combinare ciò in qualsiasi cosa tu voglia, ma tieni presente che non ci sono coppie add-horizontal phaddq, solo verticali paddq.

phaddd è simile a ciò che si desidera, ma senza l'allargamento: la metà inferiore del risultato è la somma delle coppie orizzontali nel primo operando, la metà alta è la somma delle coppie orizzontali nel secondo operando. Vale solo la pena di usarlo se hai bisogno di tutti quei risultati e non li combinerai ulteriormente. (Vale a dire che di solito è più veloce mescolare e aggiungere in verticale invece di eseguire phadd per sommare orizzontalmente un accumulatore di vettori alla fine di una riduzione. E se si sommano tutto in un risultato, si eseguono somme verticali normali finché non si scende a un registro.) phaddd potrebbe essere implementato in hardware per essere veloce come paddd (latenza a ciclo singolo e velocità effettiva), ma non è in alcuna AMD o CPU Intel.


Come Mysticial commentato, SSE4.1 pmovzxdq/pmovsxdq sono esattamente quello che ti serve, e può anche farlo al volo, come parte di un carico da una posizione di memoria 64b (contenente due interi 32b).

SSE4.1 è stato introdotto con Intel Penryn, 2nd gen Core2 (45nm die shrink core2), la generazione precedente a Nehalem. Ritornare a un percorso di codice non vettoriale su CPU più vecchie potrebbe essere ok, a seconda di quanto ci si preoccupa di non essere lenti sulle CPU che sono già vecchie e lente.


Senza SSE4.1:

Unsigned zero estensione è facile. Come ha risposto pmdj, basta usare punpck* lo e hi per decomprimere con zero.

Se i numeri interi sono firmati, è necessario eseguire manualmente l'estensione di segno.

Non c'è psraq, solo psrad (Dword aritmetico a destra con spostamento a pacchetto) e psraw. Se ci fosse, potresti disfare i bagagli con se stesso e poi con l'aritmetico spostamento a destra di 32b.

Invece, probabilmente abbiamo bisogno di generare un vettore in cui ogni elemento è trasformato nel suo bit di segno. Quindi mescolare quello con un vettore decompresso (ma pblendw è SSE4.1 anche, quindi dovremmo usare por).

O meglio, decomprimere il vettore originale con un vettore di maschere di segno.

# 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)) 

Questo dovrebbe essere eseguito con una latenza di 2 cicli per entrambi i risultati su Intel SnB o IvB. Haswell e in seguito hanno solo una porta shuffle (quindi non possono eseguire entrambi gli inss punpck in parallelo), quindi xmm2 verrà ritardato per un altro ciclo. Le CPU Intel Pre-SnB di solito hanno un collo di bottiglia sul frontend (decodificatori, ecc.) Con istruzioni vettoriali, perché spesso hanno una media superiore a 4B per insn.

Spostando l'originale anziché la copia accorcia la catena dipendenza per qualunque produce xmm0, per CPU senza spostare eliminazione (movimentazione mov istruzioni allo stadio di registro-rinomina, quindi sono latenza zero. Intel solo, e solo su IvB e versioni successive.) Con le istruzioni AVX a 3 operandi, non è necessario lo movdqa o il 3 ° registro, ma in ogni caso è possibile utilizzare lo vpmovsx per il low64. Per firmare-estendere l'alto 64, si sarebbe probabilmente psrldq byte spostare l'alta 64 verso il basso 64.

O movhlps o punpckhqdq self,self ad utilizzare un'istruzione più breve-to-codifica. (O AVX2 vpmovsx ad una reg 256b, e quindi vextracti128 la tomaia 128, per ottenere entrambi 128b risultati con solo due istruzioni.)


differenza GP-registro turni (es sar eax, 31), vettore sposta saturare il conteggio invece di mascheramento. Lasciare il bit del segno originale come LSB (spostandosi di 31) invece di una sua copia (spostandosi di 32) funziona bene. Ha il vantaggio di non richiedere un grande commento con il codice che lo spiega per le persone che si preoccuperebbero quando hanno visto psrad xmm0, 32.

Problemi correlati