2011-12-15 21 views
7

Trong SSE3, hướng dẫn PALIGNR thực hiện như sau:_mm_alignr_epi8 (PALIGNR) tương đương trong AVX2

PALIGNR concatenates the destination operand (the first operand) and the source operand (the second operand) into an intermediate composite, shifts the composite at byte granularity to the right by a constant immediate, and extracts the right-aligned result into the destination.

Tôi hiện đang ở giữa porting mã SSE4 tôi để sử dụng hướng dẫn AVX2 và làm việc trên 256bit đăng ký thay vì 128bit. Naively, tôi tin rằng chức năng nội tại _mm256_alignr_epi8 (VPALIGNR) thực hiện các hoạt động tương tự như _mm_alignr_epi8 chỉ trên thanh ghi 256bit. Đáng buồn thay tuy nhiên, đó không phải là chính xác trường hợp. Trong thực tế, _mm256_alignr_epi8 xử lý thanh ghi 256bit là 2 thanh ghi 128bit và thực hiện 2 thao tác "căn chỉnh" trên hai thanh ghi 128bit lân cận. Thực hiện hiệu quả hoạt động tương tự như _mm_alignr_epi8 nhưng trên 2 thanh ghi cùng một lúc. Nó thể hiện rõ nhất ở đây: _mm256_alignr_epi8

Hiện nay giải pháp của tôi là tiếp tục sử dụng _mm_alignr_epi8 bằng cách phân chia các YMM (256bit) đăng ký vào hai XMM (128bit) đăng ký (cao và thấp), như vậy:

__m128i xmm_ymm1_hi = _mm256_extractf128_si256(ymm1, 0); 
__m128i xmm_ymm1_lo = _mm256_extractf128_si256(ymm1, 1); 
__m128i xmm_ymm2_hi = _mm256_extractf128_si256(ymm2, 0); 
__m128i xmm_ymm_aligned_lo = _mm_alignr_epi8(xmm_ymm1_lo, xmm_ymm1_hi, 1); 
__m128i xmm_ymm_aligned_hi = _mm_alignr_epi8(xmm_ymm2_hi, xmm_ymm1_lo, 1); 
__m256i xmm_ymm_aligned = _mm256_set_m128i(xmm_ymm_aligned_lo, xmm_ymm_aligned_hi); 

Điều này làm việc, nhưng phải có một cách tốt hơn, phải không? Có một hướng dẫn AVX2 "tổng quát" có lẽ nên sử dụng để có được kết quả tương tự không?

Trả lời

2

Giải pháp duy nhất tôi đã có thể đưa ra cho việc này là:

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    if (n < 16) 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 0); 
    __m128i v0l = _mm256_extractf128_si256(v0, 1); 
    __m128i v1h = _mm256_extractf128_si256(v1, 0); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
    else 
    { 
    __m128i v0h = _mm256_extractf128_si256(v0, 1); 
    __m128i v0l = _mm256_extractf128_si256(v1, 0); 
    __m128i v1h = _mm256_extractf128_si256(v1, 1); 
    __m128i vouth = _mm_alignr_epi8(v0l, v0h, n - 16); 
    __m128i voutl = _mm_alignr_epi8(v1h, v0l, n - 16); 
    __m256i vout = _mm256_set_m128i(voutl, vouth); 
    return vout; 
    } 
} 

mà tôi nghĩ là khá nhiều giống với giải pháp của bạn ngoại trừ nó cũng xử lý sự thay đổi của> = 16 byte.

+0

yup, đó là giải pháp tương tự. nhưng nếu đây là cách duy nhất thì nó có vẻ như một sự giám sát lớn bởi các nhà thiết kế của các chỉ dẫn AVX2 – eladidan

+0

Tôi không thể làm được điều này để biên dịch ... Tôi nhận được lỗi biên dịch: "lỗi thảm khốc: tham số nội tại phải là giá trị ngay lập tức" trên dòng sau: "__m128i vouth = _mm_alignr_epi8 (v0l, v0h, n);". Ngụ ý, bởi vì n không phải là một sự bất tử. Làm thế nào bạn có thể bỏ qua điều này? Tôi đang sử dụng bộ biên dịch Intel C++ – eladidan

+0

Nó hoạt động với tôi, miễn là n là hằng số biên dịch - tôi đang sử dụng trình biên dịch ICC của Intel, nhưng biên dịch thành C thay vì C++ nếu điều đó tạo ra bất kỳ sự khác biệt nào, và nó cũng làm việc cho tôi với gcc. –

4

Bạn đang sử dụng palignr để làm gì? Nếu nó chỉ để xử lý dữ liệu sai lệch, chỉ cần sử dụng tải không đúng giá trị thay thế; chúng thường "đủ nhanh" trên kiến ​​trúc Intel µ hiện đại (và sẽ giúp bạn tiết kiệm rất nhiều kích thước mã).

Nếu bạn cần palignr hành vi giống như đối với một số lý do khác, bạn có thể đơn giản tận dụng lợi thế của hỗ trợ tải chưa được căn chỉnh để thực hiện theo cách miễn phí. Trừ khi bạn hoàn toàn bị giới hạn tải lưu trữ, đây có lẽ là thành ngữ ưu tiên.

static inline __m256i _mm256_alignr_epi8(const __m256i v0, const __m256i v1, const int n) 
{ 
    // Do whatever your compiler needs to make this buffer 64-byte aligned. 
    // You want to avoid the possibility of a page-boundary crossing load. 
    char buffer[64]; 

    // Two aligned stores to fill the buffer. 
    _mm256_store_si256((__m256i *)&buffer[0], v0); 
    _mm256_store_si256((__m256i *)&buffer[32], v1); 

    // Misaligned load to get the data we want. 
    return _mm256_loadu_si256((__m256i *)&buffer[n]); 
} 

Nếu bạn có thể cung cấp thêm thông tin về cách chính xác bạn đang sử dụng palignr, tôi có lẽ có thể hữu ích hơn.

+0

Độ trễ sẽ không tốt lắm, vì tải sẽ có thêm 10 chu kỳ trễ từ một gian hàng chuyển tiếp lưu trữ trên CPU Intel. Tuy nhiên, IDK nếu các quầy giao nhận lưu trữ là một vấn đề thông lượng. Họ có thể không. –

+1

@PeterCordes: Không có nguy cơ thông lượng, chỉ có độ trễ. Cách tiếp cận phác thảo ở đây có ý nghĩa trong các tình huống mà cửa hàng có thể được treo để ẩn độ trễ hoặc dữ liệu được lưu trữ có thể được sử dụng lại để trích xuất nhiều loại căn chỉnh khác nhau. Tất nhiên, chúng tôi có hai phím nguồn trong AVX-512, thường là giải pháp tốt hơn. –

+0

Oh điểm tốt, điều này là tuyệt vời để tạo ra các cửa sổ khác nhau vào cùng một hai vectơ. Nó cũng tốt cho một số thay đổi thời gian chạy biến. –