2016-12-26 14 views
6

Tôi đang triển khai chuyển đổi giữa các loại SSE và tôi thấy rằng việc triển khai chuyển đổi mở rộng int8-> int64 cho các mục tiêu trước SSE4.1 là cồng kềnh.Làm thế nào để thực hiện hiệu quả chuyển đổi int8/int64 với SSE?

Việc thực hiện đơn giản sẽ là:

inline __m128i convert_i8_i64(__m128i a) 
{ 
#ifdef __SSE4_1__ 
    return _mm_cvtepi8_epi64(a); 
#else 
    a = _mm_unpacklo_epi8(a, a); 
    a = _mm_unpacklo_epi16(a, a); 
    a = _mm_unpacklo_epi32(a, a); 
    return _mm_srai_epi64(a, 56); // missing instrinsic! 
#endif 
} 

Nhưng kể từ _mm_srai_epi64 không tồn tại cho đến khi AVX-512, có hai tùy chọn vào thời điểm này:

  • thực hiện _mm_srai_epi64, hoặc
  • triển khai convert_i8_i64 theo cách khác.

Tôi không chắc giải pháp nào là giải pháp hiệu quả nhất. Bất kỳ ý tưởng?

Trả lời

4

Nội tại giải nén được sử dụng ở đây một cách hài hước. Chúng "trùng lặp" dữ liệu, thay vì thêm tiện ích mở rộng dấu, như mong đợi. Ví dụ, trước khi phiên đầu tiên bạn có trong sổ đăng ký của bạn như sau

x x x x x x x x x x x x x x a b 

Nếu bạn chuyển đổi ab-16 bit, bạn sẽ nhận được điều này:

x x x x x x x x x x x x A a B b 

Đây AB là sign- các tiện ích mở rộng của ab, tức là cả hai đều là 0 hoặc -1.

Thay vì điều này, mã của bạn mang đến cho

x x x x x x x x x x x x a a b b 

Và sau đó bạn chuyển nó sang kết quả thích hợp bằng cách thay đổi ngay.

Tuy nhiên, bạn không bắt buộc phải sử dụng cùng một toán hạng hai lần trong nội dung "giải nén" nội tại. Bạn có thể nhận được kết quả mong muốn nếu bạn "giải nén" hai thanh ghi sau:

x x x x x x x x x x x x x x a b 
x x x x x x x x x x x x x x A B 

Đó là:

a = _mm_unpacklo_epi8(a, _mm_srai_epi8(a, 8)); 

(nếu đó _mm_srai_epi8 nội tại thực sự tồn tại)


Bạn có thể áp dụng cùng một ý tưởng cho giai đoạn cuối cùng của chuyển đổi của bạn. Bạn muốn "giải nén" hai thanh ghi sau:

x x x x x x x x A A A a B B B b 
x x x x x x x x A A A A B B B B 

Để có được chúng, phải chuyển dữ liệu 32-bit:

_mm_srai_epi32(a, 24) 
_mm_srai_epi32(a, 32) 

Vì vậy, cuối cùng "giải nén" là

_mm_unpacklo_epi32(_mm_srai_epi32(a, 24), _mm_srai_epi32(a, 32)); 
2

Với SSSE3, bạn có thể sử dụng pshufb để tránh hầu hết các gói.Sử dụng a/A ký hiệu Anatoly của:

;; input in xmm0    ;; x x x x x x x x | x x x x x x a b 
pshufb xmm0, [low_to_upper] ;; a 0 0 0 0 0 0 0 | b 0 0 0 0 0 0 0 
psrad xmm0, 24    ;; A A A a 0 0 0 0 | B B B b 0 0 0 0 
pshufb xmm0, [bcast_signextend]; A A A A A A A a | B B B B B B B b 

Without SSSE3, tôi nghĩ bạn có thể làm điều gì đó với PSHUFLW, PSHUFD, và có lẽ POR thay vì một số bước PUNPCK. Nhưng không có gì tôi đã nghĩ là thực sự tốt hơn so với các gói, trừ khi bạn đang ở trên một CPU Core2 hoặc chậm shuffle khác, nơi pshuflw là nhanh hơn punpcklbw.

Các vấn đề liên quan