2010-03-25 34 views
6

(Tôi là một newbie để SSE/asm, lời xin lỗi nếu điều này là rõ ràng hoặc không cần thiết)transpose cho 8 thanh ghi của các nguyên tố 16-bit trên SSE2/SSSE3

Có cách nào tốt hơn để transpose 8 thanh ghi SSE chứa Giá trị 16 bit so với thực hiện 24 unpck [lh] ps và 8/16 + shuffles và sử dụng 8 thanh ghi bổ sung? (Lưu ý sử dụng tối đa SSSE 3 hướng dẫn, Intel Merom, aka thiếu BLEND * từ SSE4.)

Giả sử bạn có thanh ghi v [0-7] và sử dụng t0-t7 làm thanh ghi aux. Trong giả intrinsics mã:

/* 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 */ 

Mỗi unpck * mất 3 chu kỳ của độ trễ, hoặc 2 cho thông lượng đối ứng (báo cáo của Agner.) Đây là tiêu diệt một phần lớn của tăng hiệu suất sử dụng SSE (trên mã này) vì đăng ký nhảy này mất gần một chu kỳ cho mỗi phần tử. Tôi đã cố gắng để hiểu tập tin asm x264 cho x86 transpose nhưng không hiểu các macro.

Cảm ơn!

Trả lời

6

Vâng, bạn có thể làm điều đó trong 24 hướng dẫn tổng:

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) 

Hãy cho tôi biết nếu bạn cần biết thêm chi tiết, nhưng nó khá rõ ràng.

+0

Đẹp nhất, bạn đời! Bất kỳ cơ hội nào bạn có thể chỉ cho tôi theo một hướng nào đó để tìm thêm các biến đổi cơ bản với SSE? – alecco

+1

@aleccolocco: không có nhiều tài liệu tốt về SSE ngoài kia, thật không may, ít nhất là cho các chủ đề nâng cao hơn. Tôi khuyên bạn nên xem các tài nguyên AltiVec (ví dụ: trên developer.apple.com) - rất nhiều kỹ thuật AltiVec dịch dễ dàng sang SSE. –

+0

Tin vui: Tôi đã làm được. Tin xấu: chỉ có 5% đạt được hiệu suất trên 1 triệu yếu tố. Nhưng cảm ơn, tôi đã học được một số thủ thuật SSE thú vị! – alecco

0

Ý tưởng của tôi đến từ này http://www.randombit.net/bitbashing/programming/integer_matrix_transpose_in_sse2.html

tôi sẽ phân khúc một 8x8 tới bốn 4x4 và hơn làm các trick đề cập. cuối cùng hoán đổi khối (0,1) và chặn (1,0)

tuy nhiên, tôi vẫn không hiểu thủ thuật của Paul R. Paul, bạn sẽ cho tôi thêm một số truy cập?

+0

Liên kết đã chết, nhưng bạn có thể hồi sinh: http://wayback.archive.org/web/20100111104515/http://www.randombit.net/bitbashing/programming/integer_matrix_transpose_in_sse2.html – Ekin

5

Tôi phải tự làm điều này, vì vậy đây là kết quả cuối cùng của tôi. Lưu ý rằng các hướng dẫn tải và lưu trữ tôi đã sử dụng là dành cho mảng được liên kết 16 byte, được khai báo sử dụng m128i * mảng = (__m128i *) _mm_malloc (N * sizeof (uint16_t), 16); HOẶC mảng int16_t [N] __ thuộc tính ((căn chỉnh (16)));

__m128i *p_input = (__m128i*)array; 
__m128i *p_output = (__m128i*)array; 
__m128i a = _mm_load_si128(p_input++); 
__m128i b = _mm_load_si128(p_input++); 
__m128i c = _mm_load_si128(p_input++); 
__m128i d = _mm_load_si128(p_input++); 
__m128i e = _mm_load_si128(p_input++); 
__m128i f = _mm_load_si128(p_input++); 
__m128i g = _mm_load_si128(p_input++); 
__m128i h = _mm_load_si128(p_input); 

__m128i a03b03 = _mm_unpacklo_epi16(a, b); 
__m128i c03d03 = _mm_unpacklo_epi16(c, d); 
__m128i e03f03 = _mm_unpacklo_epi16(e, f); 
__m128i g03h03 = _mm_unpacklo_epi16(g, h); 
__m128i a47b47 = _mm_unpackhi_epi16(a, b); 
__m128i c47d47 = _mm_unpackhi_epi16(c, d); 
__m128i e47f47 = _mm_unpackhi_epi16(e, f); 
__m128i g47h47 = _mm_unpackhi_epi16(g, h); 

__m128i a01b01c01d01 = _mm_unpacklo_epi32(a03b03, c03d03); 
__m128i a23b23c23d23 = _mm_unpackhi_epi32(a03b03, c03d03); 
__m128i e01f01g01h01 = _mm_unpacklo_epi32(e03f03, g03h03); 
__m128i e23f23g23h23 = _mm_unpackhi_epi32(e03f03, g03h03); 
__m128i a45b45c45d45 = _mm_unpacklo_epi32(a47b47, c47d47); 
__m128i a67b67c67d67 = _mm_unpackhi_epi32(a47b47, c47d47); 
__m128i e45f45g45h45 = _mm_unpacklo_epi32(e47f47, g47h47); 
__m128i e67f67g67h67 = _mm_unpackhi_epi32(e47f47, g47h47); 

__m128i a0b0c0d0e0f0g0h0 = _mm_unpacklo_epi64(a01b01c01d01, e01f01g01h01); 
__m128i a1b1c1d1e1f1g1h1 = _mm_unpackhi_epi64(a01b01c01d01, e01f01g01h01); 
__m128i a2b2c2d2e2f2g2h2 = _mm_unpacklo_epi64(a23b23c23d23, e23f23g23h23); 
__m128i a3b3c3d3e3f3g3h3 = _mm_unpackhi_epi64(a23b23c23d23, e23f23g23h23); 
__m128i a4b4c4d4e4f4g4h4 = _mm_unpacklo_epi64(a45b45c45d45, e45f45g45h45); 
__m128i a5b5c5d5e5f5g5h5 = _mm_unpackhi_epi64(a45b45c45d45, e45f45g45h45); 
__m128i a6b6c6d6e6f6g6h6 = _mm_unpacklo_epi64(a67b67c67d67, e67f67g67h67); 
__m128i a7b7c7d7e7f7g7h7 = _mm_unpackhi_epi64(a67b67c67d67, e67f67g67h67); 

_mm_store_si128(p_output++, a0b0c0d0e0f0g0h0); 
_mm_store_si128(p_output++, a1b1c1d1e1f1g1h1); 
_mm_store_si128(p_output++, a2b2c2d2e2f2g2h2); 
_mm_store_si128(p_output++, a3b3c3d3e3f3g3h3); 
_mm_store_si128(p_output++, a4b4c4d4e4f4g4h4); 
_mm_store_si128(p_output++, a5b5c5d5e5f5g5h5); 
_mm_store_si128(p_output++, a6b6c6d6e6f6g6h6); 
_mm_store_si128(p_output, a7b7c7d7e7f7g7h7); 
Các vấn đề liên quan