On Intel, mã của bạn sẽ được tối ưu. Một hướng dẫn 1-uop là tốt nhất bạn sẽ nhận được. (Ngoại trừ bạn có thể muốn sử dụng vpermps
để tránh bất kỳ rủi ro nào cho sự chậm trễ bỏ qua int/FP, nếu vectơ đầu vào của bạn được tạo bởi lệnh pd
thay vì tải hoặc một thứ gì đó. thường là tốt trên Intel, nhưng tôi ít chắc chắn về việc cho ăn kết quả của một lệnh FP để trộn ngẫu nhiên.)
Mặc dù nếu điều chỉnh cho Intel, bạn có thể thử thay đổi mã xung quanh để bạn có thể trộn vào đáy 64 -bộ phận của mỗi làn 128b, để tránh sử dụng trộn ngẫu nhiên làn đường. (Sau đó, bạn chỉ có thể sử dụng vshufps ymm
, hoặc nếu điều chỉnh cho KNL, vpermilps
từ 2-input vshufps
là chậm hơn.)
Với AVX512, có _mm256_cvtepi64_epi32
(vpmovqd
) mà gói các yếu tố trên làn xe, với cắt ngắn.
On Ryzen, shuffles làn vượt chậm. Agner Fog không có số cho vpermd
, nhưng anh ta liệt kê vpermps
(có thể sử dụng cùng phần cứng nội bộ) ở 3 uops, 5c độ trễ, một cho mỗi thông lượng 4c.
vextractf128 xmm, ymm, 1
rất hiệu quả trên Ryzen (độ trễ 1c, thông lượng 0.33c), không đáng ngạc nhiên vì nó theo dõi thanh ghi 256b là hai nửa 128b. shufps
cũng hiệu quả (độ trễ 1c, thông lượng 0.5c) và sẽ cho phép bạn trộn hai thanh ghi 128b vào kết quả bạn muốn.
Điều này cũng giúp bạn tiết kiệm 2 thanh ghi cho các mặt nạ trộn 2 vpermps
bạn không cần nữa.
Vì vậy, tôi muốn đề nghị:
__m256d x = /* computed here */;
// Tuned for Ryzen. Sub-optimal on Intel
__m128 hi = _mm_castpd_ps(_mm256_extractf128_pd(x, 1));
__m128 lo = _mm_castpd_ps(_mm256_castpd256_pd128(x));
__m128 odd = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(3,1,3,1));
__m128 even = _mm_shuffle_ps(lo, hi, _MM_SHUFFLE(2,0,2,0));
On Intel, sử dụng 3 shuffles thay vì 2 cung cấp cho bạn 2/3rds của thông lượng tối ưu, với độ trễ 1c thêm cho kết quả đầu tiên.
Vì vậy, bạn muốn trích xuất các phần tử 32 bit lẻ hoặc được đánh số? ví dụ như AVX512 '_mm256_cvtepi64_epi32' (' vpmovqd')? Tôi không nghĩ rằng bạn sẽ đánh bại 1 lệnh shuffle với độ trễ 3 chu kỳ, bởi vì các nút xoay ngang làn đường luôn có độ trễ 3c trên CPU Intel. Giải pháp 'vpermd' của bạn có thông lượng chu trình đơn. –
Nếu bạn cần nó nhanh hơn, bạn sẽ phải làm cho mã xung quanh sử dụng nó ít hơn, hoặc không yêu cầu vượt qua làn đường hoặc một cái gì đó! Hoặc có thể bằng cách nào đó đóng gói hai nguồn vào một kết quả 256b với 'shufps' (ngoại trừ nó không phải là làn đường giao nhau để nó không giải quyết được vấn đề của bạn, và không có lệnh' vpackqd' và hướng dẫn đóng gói nào cũng không bị vượt qua.) –
@PeterCordes, vâng, tôi muốn trích xuất các phần tử 32 bit lẻ hoặc được đánh số từ một thanh ghi 256 bit sang thanh ghi 128 bit. Cảm ơn bạn đã tham khảo AVX512! Tôi không có nó trên Ryzen 1800X, nhưng mong muốn di chuyển đến nó một lần ... Những phần tử 32 bit này là phần cao và thấp của đôi 64-bit, vì vậy tôi không thấy một cách để thay đổi mã xung quanh . –