(Je suis un débutant à SSE / ASM, mes excuses si cela est évident ou redondant)
Y a-t-il un meilleur moyen de transposer 8 registres de SSE contenant des valeurs de 16 bits que de 24 pb et 8 / 16 + Shuffles et utiliser 8 registres supplémentaires? (Remarque Utilisation des instructions SSSE 3, Intel Merom, aka manquant de mélange * de SSE4.) P>
Dites que vous avez des registres V [0-7] et utilisez T0-T7 comme des registres AUX. Code Pseudo Intrinsics: P>
/* Phase 1: process lower parts of the registers */ /* Level 1: work first part of the vectors */ /* v[0] A0 A1 A2 A3 A4 A5 A6 A7 ** v[1] B0 B1 B2 B3 B4 B5 B6 B7 ** v[2] C0 C1 C2 C3 C4 C5 C6 C7 ** v[3] D0 D1 D2 D3 D4 D5 D6 D7 ** v[4] E0 E1 E2 E3 E4 E5 E6 E7 ** v[5] F0 F1 F2 F3 F4 F5 F6 F7 ** v[6] G0 G1 G2 G3 G4 G5 G6 G7 ** v[7] H0 H1 H2 H3 H4 H5 H6 H7 */ t0 = unpcklps (v[0], v[1]); /* Extract first half interleaving */ t1 = unpcklps (v[2], v[3]); /* Extract first half interleaving */ t2 = unpcklps (v[4], v[5]); /* Extract first half interleaving */ t3 = unpcklps (v[6], v[7]); /* Extract first half interleaving */ t0 = pshufhw (t0, 0xD8); /* Flip middle 2 high */ t0 = pshuflw (t0, 0xD8); /* Flip middle 2 low */ t1 = pshufhw (t1, 0xD8); /* Flip middle 2 high */ t1 = pshuflw (t1, 0xD8); /* Flip middle 2 low */ t2 = pshufhw (t2, 0xD8); /* Flip middle 2 high */ t2 = pshuflw (t2, 0xD8); /* Flip middle 2 low */ t3 = pshufhw (t3, 0xD8); /* Flip middle 2 high */ t3 = pshuflw (t3, 0xD8); /* Flip middle 2 low */ /* t0 A0 B0 A1 B1 A2 B2 A3 B3 (A B - 0 1 2 3) ** t1 C0 D0 C1 D1 C2 D2 C3 D3 (C D - 0 1 2 3) ** t2 E0 F0 E1 F1 E2 F2 E3 F3 (E F - 0 1 2 3) ** t3 G0 H0 G1 H1 G2 H2 G3 H3 (G H - 0 1 2 3) */ /* L2 */ t4 = unpcklps (t0, t1); t5 = unpcklps (t2, t3); t6 = unpckhps (t0, t1); t7 = unpckhps (t2, t3); /* t4 A0 B0 C0 D0 A1 B1 C1 D1 (A B C D - 0 1) ** t5 E0 F0 G0 H0 E1 F1 G1 H1 (E F G H - 0 1) ** t6 A2 B2 C2 D2 A3 B3 C3 D3 (A B C D - 2 3) ** t7 E2 F2 G2 H2 E3 F3 G3 H3 (E F G H - 2 3) */ /* Phase 2: same with higher parts of the registers */ /* A A0 A1 A2 A3 A4 A5 A6 A7 ** B B0 B1 B2 B3 B4 B5 B6 B7 ** C C0 C1 C2 C3 C4 C5 C6 C7 ** D D0 D1 D2 D3 D4 D5 D6 D7 ** E E0 E1 E2 E3 E4 E5 E6 E7 ** F F0 F1 F2 F3 F4 F5 F6 F7 ** G G0 G1 G2 G3 G4 G5 G6 G7 ** H H0 H1 H2 H3 H4 H5 H6 H7 */ t0 = unpckhps (v[0], v[1]); t0 = pshufhw (t0, 0xD8); /* Flip middle 2 high */ t0 = pshuflw (t0, 0xD8); /* Flip middle 2 low */ t1 = unpckhps (v[2], v[3]); t1 = pshufhw (t1, 0xD8); /* Flip middle 2 high */ t1 = pshuflw (t1, 0xD8); /* Flip middle 2 low */ t2 = unpckhps (v[4], v[5]); t2 = pshufhw (t2, 0xD8); /* Flip middle 2 high */ t2 = pshuflw (t2, 0xD8); /* Flip middle 2 low */ t3 = unpckhps (v[6], v[7]); t3 = pshufhw (t3, 0xD8); /* Flip middle 2 high */ t3 = pshuflw (t3, 0xD8); /* Flip middle 2 low */ /* t0 A4 B4 A5 B5 A6 B6 A7 B7 (A B - 4 5 6 7) ** t1 C4 D4 C5 D5 C6 D6 C7 D7 (C D - 4 5 6 7) ** t2 E4 F4 E5 F5 E6 F6 E7 F7 (E F - 4 5 6 7) ** t3 G4 H4 G5 H5 G6 H6 G7 H7 (G H - 4 5 6 7) */ /* Back to first part, v[0-3] can be re-written now */ /* L3 */ v[0] = unpcklpd (t4, t5); v[1] = unpckhpd (t4, t5); v[2] = unpcklpd (t6, t7); v[3] = unpckhpd (t6, t7); /* v[0] = A0 B0 C0 D0 E0 F0 G0 H0 ** v[1] = A1 B1 C1 D1 E1 F1 G1 H1 ** v[2] = A2 B2 C2 D2 E2 F2 G2 H2 ** v[3] = A3 B3 C3 D3 E3 F3 G3 H3 */ /* Back to second part, t[4-7] can be re-written now... */ /* L2 */ t4 = unpcklps (t0, t1); t5 = unpcklps (t2, t3); t6 = unpckhps (t0, t1); t7 = unpckhps (t2, t3); /* t4 A4 B4 C4 D4 A5 B5 C5 D5 (A B C D - 4 5) ** t5 E4 F4 G4 H4 E5 F5 G5 H5 (E F G H - 4 5) ** t6 A6 B6 C6 D6 A7 B7 C7 D7 (A B C D - 6 7) ** t7 E6 F6 G6 H6 E7 F7 G7 H7 (E F G H - 6 7) */ /* L3 */ v[4] = unpcklpd (t4, t5); v[5] = unpckhpd (t4, t5); v[6] = unpcklpd (t6, t7); v[7] = unpckhpd (t6, t7); /* v[4] = A4 B4 C4 D4 E4 F4 G4 H4 ** v[5] = A5 B5 C5 D5 E5 F5 G5 H5 ** v[6] = A6 B6 C6 D6 E6 F6 G6 H6 ** v[7] = A7 B7 C7 D7 E7 F7 G7 H7 */
3 Réponses :
Oui, vous pouvez le faire dans 24 instructions TOTAL:
8 x _mm_unpacklo_epi16/_mm_unpackhi_epi16 (PUNPCKLWD/PUNPCKHWD) 8 x _mm_unpacklo_epi32/_mm_unpackhi_epi32 (PUNPCKLDQ/PUNPCKHDQ) 8 x _mm_unpacklo_epi64/_mm_unpackhi_epi64 (PUNPCKLQDQ/PUNPCKHQDQ)
Nice, mate! Par hasard pourriez-vous me signaler dans une certaine direction où trouver plus de transformations de base avec SSE?
@aleccolocco: Il n'y a pas beaucoup de bon matériel sur SSE, malheureusement, au moins pour les sujets plus avancés. Je recommande de regarder les ressources d'Altivec (par exemple sur développeur.apple.com) - Beaucoup de techniques d'Altivec se traduisent facilement à SSE.
Bonne nouvelle: j'ai réussi à le faire. Bad News: Seulement 5% de performance de performance mesurant sur des éléments 1M. Mais merci, j'ai appris des astuces SSE cool!
@aleccolocco: Si vous faites simplement une transposition de mémoire à mémoire et rien d'autre, vos performances peuvent bien être limitées par la bande passante de la mémoire, etc. En général, vous obtiendrez une meilleure performance globale si vous pouvez combiner la transposition avec d'autres opérations . Notez également que SSE Performance varie extrêmement i> entre différentes familles de la CPU: par exemple. Avant Core 2 Duo = Abysmal, Core 2 Duo = Bon, Core I7 = Rocks i>!
@Paul r Oueah. Je suis en train de mettre en œuvre une "mise en œuvre efficace du tri sur l'architecture multi-noyau SIMD CPU" et quelques autres choses. Le merom de mon cahier semble être de 8 fois plus lentement que leur Xeon Penryn et ne veut même pas savoir à quel point ce serait plus rapide sur I7. Néanmoins, les éléments de 1 m ne doivent être que 2 Mo et bien à l'intérieur de la L2 ici (donc ce n'est pas la bande passante, je pense.) Bravo!
@aleccolocco: OK, oui, c'est probablement votre CPU qui est le facteur limitant alors. Notez également que cette planification d'instructions peut être un problème si vous utilisez ASM - vous obtiendrez probablement de meilleurs résultats à l'aide de C InstrinSics (_mm_unpackx_xxx) et laissez le compilateur C. ICC est le meilleur compilateur pour cela, suivi de GCC, suivi du Studio Visual Execrable. De plus, si vous pouvez exécuter sur un processeur 64 bits, compilez-la avec -M64 afin que vous obteniez 16 registres de SSE plutôt que 8.
@PaulR: La différence de performance est en partie due à la "mur de 64 bits" en SSE: que l'unité SSE de 128 bits est formée à partir de deux unités distinctes 64 bits, ce qui entraîne une pénalité chaque fois que les données doivent croiser le 64 bits. frontière. (Chaque unité de 64 bits a ses propres registres) Intel.com/technology/itj/2008/v12i3/3-paper/3-super.htm Essayez d'utiliser le formulaire d'affectation unique statique, pour éviter les problèmes avec de fausses dépendances de données.
@Rwong: Cela ne s'applique vraiment qu'aux anciens processeurs (avant le noyau 2) - du noyau 2 à partir d'Intel est allé pour une implémentation complète de SSE de 128 bits
Étant donné que ces fonctions accepte __ m128i code>, cette approche ne fonctionne pas avec une matrice de flotteur 8x8?
@Davids: Vous feriez normalement une transposition 4x4 avec des flotteurs, plutôt que 8x8, car vous n'obtenez que 4 flotteurs par vecteur (c'est-à-dire que vous utilisez 4 vecteurs). Mais le principe est le même, et vous pouvez toujours utiliser des instructions en integer SSE pour faire le mélange. Et bien sûr, vous pouvez construire des transpositions plus importants à l'aide de la transposition vectorielle 4x4 en tant que bloc de construction.
@Paulr, oui la pensée. Peut-être que je peux essayer d'utiliser AVX-256, car je puisse vous installer huit 32 bits (flotteurs) dans chaque registre .. Toute réflexion sur cette approche?
@Davids: Oui, vous pourriez faire 8x8 avec AVX, mais c'est un peu plus fidèle à cause des voies divisées.
@Paulr: Je me suis traité avec cela pendant un moment, mais échouez à chaque fois. J'aimerais vraiment avoir une alternative de travail à l'aide d'AVX2. Ne pas détourner plus de ce fil: y a-t-il une façon de vous contacter? Si vous voulez garder votre email privé, vous trouverez le mien au bas de la page: Davidsteinsland.net/ om-meg
@Davids: Je serais heureux d'aider avec cela, mais je pense que plutôt que de le prendre hors ligne, nous devrions créer une nouvelle question, de sorte que toutes les solutions soient disponibles pour les autres à l'avenir. N'hésitez pas à poser la question, par ex. "Comment faire une transposition 8x8 (float) en utilisant AVX / AVX2?" et assurez-vous de le baliser comme simd code>,
avX code>, etc., puis je recevrai une notification automatique et peut répondre. Vous pouvez également obtenir des solutions utiles de certaines des autres geeks de Simd ici en même temps.
Mon idée vient de ce http://www.randombit.net/bitbashing/programming /Integer_matrix_transposed_in_sse2.html P>
Je segmenterais celui de 8x8 à quatre 4x4 et que de faire le tour mentionné. enfin échanger le bloc (0,1) et le bloc (1,0) p>
Cependant, je ne comprends toujours pas ce qu'est l'astuce de Paul R. Paul me donneriez-vous d'autres hits? P>
Le lien est mort, mais vous pouvez faire revivre: wayback.archive.org/web/20100111104515/http://www.randombit. net / ...
Je devais faire cela moi-même, alors voici mon résultat final. Notez que les instructions de chargement et de stockage que j'ai utilisées concernent des tableaux alignés de 16 octets, qui ont été déclarés en utilisant