Có tải trọng rõ ràng và ngầm định trong SSE.
_mm_load_si128(reinterpret_cast<__m128i*>(&cd->data[idx]));
là một tải rõ ràng
*reinterpret_cast<__m128i*>(&cd->data[idx]);
là một tải ngầm
Với một tải rõ ràng bạn hướng dẫn rõ ràng các trình biên dịch để nạp dữ liệu vào một thanh ghi XMM - đây là "chính thức" Intel cách để làm điều đó. Bạn cũng có thể kiểm soát tải là tải trọng được căn chỉnh hay không thẳng hàng bằng cách sử dụng _mm_load_si128
hoặc _mm_loadu_si128
.
Mặc dù là phần mở rộng, hầu hết các trình biên dịch cũng có thể tự động tạo các tải XMM khi bạn thực hiện type-punning, nhưng theo cách này bạn không thể kiểm soát việc tải được căn chỉnh hay không thẳng hàng. Trong trường hợp này, vì trên các CPU hiện đại không có hình phạt hiệu suất của việc sử dụng các tải không được căn chỉnh khi dữ liệu được căn chỉnh, các trình biên dịch có xu hướng sử dụng các tải không được sắp xếp phổ quát.
Một khía cạnh quan trọng khác là tải trọng tiềm ẩn bạn vi phạm các quy tắc strict aliasing, điều này có thể dẫn đến hành vi không xác định. Mặc dù cần lưu ý rằng - như một phần của phần mở rộng - các trình biên dịch hỗ trợ nội tại Intel không có xu hướng thực thi các quy tắc bí mật nghiêm ngặt về các loại trình giữ chỗ XMM như __m128
, __m128d
, __m128i
.
Tuy nhiên, tôi cho rằng tải trọng rõ ràng là sạch hơn và chống đạn hơn.
Tại sao trình biên dịch không có xu hướng thực thi quy tắc bí danh nghiêm ngặt về loại trình giữ chỗ SSE?
Các lý do 1st dối trá trong việc thiết kế intrinsics SSE: có những trường hợp rõ ràng khi bạn phải sử dụng kiểu punning, vì không có cách nào khác để sử dụng một số intrinsics. Mysticial's answer tóm tắt nó một cách hoàn hảo.
Như Cody Grey đã chỉ ra trong các nhận xét, điều đáng nói đến là các công cụ MMX lịch sử (hiện giờ được thay thế bởi SSE2) thậm chí không cung cấp các tải hoặc cửa hàng rõ ràng - bạn phải sử dụng loại punning.
Lý do thứ hai (có liên quan đến số 1) nằm trong định nghĩa loại của các loại này.
GCC của typedef
s cho các loại placeholder/SSE2 SSE trong <xmmintrin.h >
và <emmintrin.h>
:
/* The Intel API is flexible enough that we must allow aliasing with other
vector types, and their scalar components. */
typedef float __m128 __attribute__ ((__vector_size__ (16), __may_alias__));
typedef long long __m128i __attribute__ ((__vector_size__ (16), __may_alias__));
typedef double __m128d __attribute__ ((__vector_size__ (16), __may_alias__));
Mấu chốt ở đây là __may_alias__
thuộc tính, mà làm việc kiểu punning trên các loại ngay cả khi răng cưa chặt chẽ được kích hoạt với cờ -fstrict-aliasing
.
Hiện tại, kể từ clang và ICC tương thích với GCC, chúng phải tuân thủ cùng một quy ước. Vì vậy, hiện tại, trong 3 trình biên dịch này, các tải/cửa hàng tiềm ẩn được đảm bảo làm việc ngay cả với cờ -fstrict-aliasing
. Cuối cùng, MSVC không hỗ trợ bí danh nghiêm ngặt, do đó, nó thậm chí không thể là vấn đề ở đó.
Tuy nhiên, điều này không có nghĩa là bạn nên thích tải/lưu trữ ngầm hơn các cửa hàng khiêu dâm.
Có thể là (hoặc được mở rộng đến) một số trình biên dịch được xây dựng. Bạn đang sử dụng trình biên dịch C++ nào? –
@BasileStarynkevitch một trong số đó đi kèm với studio trực quan – user81993
Không phải '_ra = reinterpret_cast <__m128> (cd-> data [idx])' cũng có thể không? – Walter