Tôi đang học cách sử dụng các khả năng SIMD bằng cách viết lại thư viện xử lý hình ảnh cá nhân của mình bằng nội tại vectơ. Một chức năng cơ bản là một đơn giản "mảng +=
," tức làMảng SIMD thêm cho độ dài mảng tùy ý
void arrayAdd(unsigned char* A, unsigned char* B, size_t n) {
for(size_t i=0; i < n; i++) { B[i] += A[i] };
}
Đối với độ dài mảng tùy ý, các mã SIMD rõ ràng (giả sử thẳng hàng 16) là một cái gì đó như:
size_t i = 0;
__m128i xmm0, xmm1;
n16 = n - (n % 16);
for (; i < n16; i+=16) {
xmm0 = _mm_load_si128((__m128i*) (A + i));
xmm1 = _mm_load_si128((__m128i*) (B + i));
xmm1 = _mm_add_epi8(xmm0, xmm1);
_mm_store_si128((__m128i*) (B + i), xmm1);
}
for (; i < n; i++) { B[i] += A[i]; }
Nhưng là nó có thể làm tất cả các bổ sung có hướng dẫn SIMD không? Tôi đã nghĩ đến việc thử điều này:
__m128i mask = (0x100<<8*(n - n16))-1;
_mm_maskmoveu_si128(xmm1, mask, (__m128i*) (B + i));
cho các yếu tố bổ sung, nhưng điều đó có dẫn đến hành vi không xác định không? Các mask
nên đảm bảo không có quyền truy cập thực sự được thực hiện qua các giới hạn mảng (tôi nghĩ). Cách khác là làm các phần tử phụ trước, nhưng sau đó mảng cần được căn chỉnh theo n-n16
, điều này có vẻ không đúng.
Có một mô hình vòng vector hóa tối ưu hơn nữa không?
bạn có thể đảm bảo rằng trong mã của bạn độ dài mảng luôn bội số của 16 byte (mặc dù các yếu tố có thể ít được thực sự sử dụng), vì vậy Epilog này không bao giờ xuất hiện. Nhưng epilog thực sự không quan trọng về mặt tốc độ. – Walter