Khi biên soạn với GCC 5.2 sử dụng -std=c99
, -O3
, và -mavx2
, các sau mẫu mã tự động vectorizes (assembly here):Làm thế nào để tự động-vectorize strided viết với GCC?
#include <stdint.h>
void test(uint32_t *restrict a,
uint32_t *restrict b) {
uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
uint32_t *b_aligned = __builtin_assume_aligned(b, 32);
for (int i = 0; i < (1L << 10); i += 2) {
a_aligned[i] = 42 * b_aligned[i];
a_aligned[i+1] = 3 * a_aligned[i+1];
}
}
Nhưng mẫu mã sau đây không tự động vectorize (assembly here):
#include <stdint.h>
void test(uint32_t *restrict a,
uint32_t *restrict b) {
uint32_t *a_aligned = __builtin_assume_aligned(a, 32);
uint32_t *b_aligned = __builtin_assume_aligned(b, 32);
for (int i = 0; i < (1L << 10); i += 2) {
a_aligned[i] = 42 * b_aligned[i];
a_aligned[i+1] = a_aligned[i+1];
}
}
Sự khác biệt duy nhất giữa các mẫu là hệ số chia tỷ lệ là a_aligned[i+1]
.
Đây cũng là trường hợp của GCC 4.8, 4.9 và 5.1. Việc thêm tuyên bố volatile
vào a_aligned
sẽ ngăn chặn hoàn toàn tự động vector. Mẫu đầu tiên luôn chạy nhanh hơn lần thứ hai đối với chúng tôi, với tốc độ tăng lên rõ rệt hơn cho các loại nhỏ hơn (ví dụ: uint8_t
thay vì uint32_t
).
Có cách nào để làm mẫu mã thứ hai tự động vector hóa với GCC không?
Vì vậy, sự khác biệt duy nhất là yếu tố mở rộng (3 so với không có gì)? Thử thêm 1 làm hệ số chia tỷ lệ một cách rõ ràng. Nếu nó giải quyết được, đó là lỗi trình biên dịch. – Jeff
Hoặc thử nhận xét câu lệnh 'a_aligned [i + 1] = a_aligned [i + 1] ', hoặc viết lại nó thành' a_aligned [i + 1] * = 1'. Trình biên dịch có thể không biết phải làm gì với việc tự gán không-op của bạn ngoài việc làm chính xác những gì bạn đã nói để làm với nó. –
@ Jeff Thật vậy, sự khác biệt duy nhất là yếu tố mở rộng quy mô. Việc thêm một đoạn mã 1 không làm cho mẫu mã thứ hai tự động-vector hóa ([assembly tại đây] (https://goo.gl/dnjSaQ)). –