В GNU C __m128i
определяется как вектор 64-битных целых чисел с чем-то вроде
typedef long long __m128i __attribute__((vector_size(16), may_alias));
Использование собственного векторного синтаксиса GNU C (оператор +
) позволяет добавлять каждый элемент с размером 64-битного элемента. т.е. _mm_add_epi64
.
В вашем случае вынос из верхней части одного 32-битного элемента добавил дополнительный к 32-битному элементу над ним, потому что размер 64-битного элемента распространяет перенос между парами 32-битных элементов. (Добавление отрицательного значения в ненулевое назначение приводит к выполнению.)
Встроенный API-интерфейс Intel не определяет оператор +
для __m128
/ __m128d
/ __m128i
. Например, ваш код не будет компилироваться в MSVC.
То есть, поведение, которое вы получаете, зависит только от деталей реализации встроенных типов в заголовках GCC. Это полезно для векторов с плавающей запятой, где существует очевидный размер элемента, но для целочисленных векторов вы захотите определить свой собственный, если у вас нет 64-битных целых чисел.
Если вы хотите использовать v1 += v2;
, вы можете определить свои собственные собственные типы векторов GNU C, например,
typedef uint32_t v4ui __attribute__((vector_size(16), aligned(4)));
Заметьте, я пропустил may_alias
, поэтому безопасно приводить указатели к unsigned
, а не для чтения произвольных данных, таких как char[]
.
На самом деле GCC emmintrin.h
(SSE2) действительно определяет группу типов:
/* SSE2 */
typedef double __v2df __attribute__ ((__vector_size__ (16)));
typedef long long __v2di __attribute__ ((__vector_size__ (16)));
typedef unsigned long long __v2du __attribute__ ((__vector_size__ (16)));
typedef int __v4si __attribute__ ((__vector_size__ (16)));
typedef unsigned int __v4su __attribute__ ((__vector_size__ (16)));
typedef short __v8hi __attribute__ ((__vector_size__ (16)));
typedef unsigned short __v8hu __attribute__ ((__vector_size__ (16)));
typedef char __v16qi __attribute__ ((__vector_size__ (16)));
typedef unsigned char __v16qu __attribute__ ((__vector_size__ (16)));
Я не уверен, предназначены ли они для внешнего использования.
Собственные векторы GNU C наиболее полезны, когда вы хотите, чтобы компилятор испускал эффективный код для деления на константу времени компиляции или что-то в этом роде. например digit = v1 % 10;
и v1 /= 10;
с 16-разрядными целыми числами без знака будут компилироваться в pmulhuw
и сдвиг вправо. Но они также удобны для читабельного кода.
Существует несколько библиотек-оболочек C ++, которые переносят перегрузки операторов и имеют такие типы, как Vec4i
(4x без знака int) / Vec4u
(4x без знака int) / Vec16c
(16x со знаком char), чтобы дать вам тип система для различных типов целочисленных векторов, так что вы знаете, что получаете от v1 += v2;
или v1 >>= 2;
(сдвиг вправо - один из случаев, когда подпись имеет значение.)
например. VCL Agner Fog (лицензия GPL) или DirectXMath (лицензия MIT).