обычная арифметика: x=254; x+=3; // результат x=1
арифметика с насыщением: x=254; x+=3; // результат x=255
1.2. Расширение 3DNow!
Технология 3DNow! была введена фирмой AMD в процессорах K6-2. Это была первая технология, выполняющая потоковую обработку вещественных данных. Расширение работает с регистрами 64-битными MMX, которые представляются как два 32-битных вещественных числа с одинарной точностью. Система команд расширена 21 новой инструкцией, среди которых есть команда выборки данных в кэш L1. В процессорах Athlon и Duron набор инструкций 3DNow! был несколько дополнен новыми инструкциями для работы с вещественными числами, а также инструкциями MMX и управления кэшированием.
1.3. Расширение SSE
С процессором Intel Pentium III впервые появилось расширение SSE (Streaming SIMD Extension). Это расширение работает с независимым блоком из восьми 128-битных регистров XMM0-XMM7. Каждый регистр XMM представляет собой четыре упакованных 32-битных вещественных числа с одинарной точностью. Команды блока XMM позволяют выполнять как векторные (над всеми четырьмя значениями регистра), так и скалярные операции (только над одним самым младшим значением). Кроме инструкций с блоком XMM в расширение SSE входят и дополнительные целочисленные инструкции с регистрами MMX, а также инструкции управления кэшированием.
1.4. Расширение SSE2
В процессоре Intel Pentium 4 набор инструкций получил очередное расширение – SSE2. Оно позволяет работать с 128-битными регистрами XMM как с парой упакованных 64-битных вещественных чисел двойной точности, а также с упакованными целыми числами: 16 байт, 8 слов, 4 двойных слова или 2 учетверенных (64-битных) слова. Введены новые инструкции вещественной арифметики двойной точности, инструкции целочисленной арифметики, 128-разрядные для регистров XMM и 64-разрядные для регистров MMX. Ряд старых инструкций MMX распространили и на XMM (в 128-битном варианте). Кроме того, расширена поддержка управления кэшированием и порядком исполнения операций с памятью.
1.5. Расширение SSE3
Дальнейшее расширение системы команд – SSE3 – вводится в процессоре Intel Pentium 4 с ядром Prescott. Это набор из 13 новых инструкций, работающих с блоками XMM, FPU, в том числе двух инструкций, повышающих эффективность синхронизации потоков, в частности, при использовании технологии Hyper-Threading.
1.6. Поддержка SIMD-расширений архитектурой x86-64
Процессоры AMD Athlon64 и AMD Opteron с архитектурой x86-64 поддерживают все выше перечисленные SIMD-расширения, кроме SSE3. Кроме того, число XMM регистров у этих процессоров увеличилось до 16 (XMM0-XMM15). Подробное описание типов и команд SSE приведено в приложении.
2. Встроенные функции потокового SIMD расширения
Типы данных
Для работы с векторными данными, содержащими несколько упакованных значений, используются следующие типы:
__m64 – 64-бит (регистр MMX)
1 * 64-битное целое
2 * 32-битных целых
4 * 16-битных целых
8 * 8-битных целых.
__m128 – 128-бит (регистр XMM):
4 * 32-битных вещественных (SSE),
2 * 64-битных вещественных (SSE2),
2 * 64-битное целых (SSE2),
4 * 32-битных целых (SSE2),
8 * 16-битных целых (SSE2),
16 * 8-битных целых (SSE2).
Для наибольшей эффективности элементы таких типов данных должны быть выровнены в памяти по соответствующей границе. Например, начало массива элементов типа __m64 выравнивается по 8 байтам, а массив элементов __m128 – по 16 байтам. Статические переменные и массивы компилятор выравнивает автоматически. Динамические данные компилятор обычно выравнивает по только величине 4 байта. Если данные векторных типов оказались невыровненными, то для работы с ними следует применять специальные команды невыровненного чтения и записи (они работают медленнее обычных – выровненных). Для выделения памяти с выравниванием используется функция:
void *_mm_malloc(int size, int align)
size – объем выделяемой памяти в байтах (как в malloc),
align – выравнивание в байтах.
Для освобождения памяти, выделенной таким образом, используется функция:
void _mm_free(void *p);
Например:
float *x; // массив для обработки с помощью инструкций SSE
x=(float)_mm_malloc(N*sizeof(float),16);
// … здесь обработка …
_mm_free(x);
Встроенные функции SSE для работы с вещественными числами
Заголовочный файл xmmintrin.h содержит объявления встроенных функций (intrinnsics) SSE.
Арифметические функции
Функция | Инструкция | Операция | R0 | R1 | R2 | R3 |
_mm_add_ss | ADDSS | сложение | a0 [op] b0 | a1 | a2 | a3 |
_mm_add_ps | ADDPS | сложение | a0 [op] b0 | a1 [op] b1 | a2 [op] b2 | a3 [op] b3 |
_mm_sub_ss | SUBSS | вычитание | a0 [op] b0 | a1 | a2 | a3 |
_mm_sub_ps | SUBPS | вычитание | a0 [op] b0 | a1 [op] b1 | a2 [op] b2 | a3 [op] b3 |
_mm_mul_ss | MULSS | умножение | a0 [op] b0 | a1 | a2 | a3 |
_mm_mul_ps | MULPS | умножение | a0 [op] b0 | a1 [op] b1 | a2 [op] b2 | a3 [op] b3 |
_mm_div_ss | DIVSS | деление | a0 [op] b0 | a1 | a2 | a3 |
_mm_div_ps | DIVPS | деление | a0 [op] b0 | a1 [op] b1 | a2 [op] b2 | a3 [op] b3 |
_mm_sqrt_ss | SQRTSS | квадратный корень | [op] a0 | a1 | a2 | a3 |
_mm_sqrt_ps | SQRTPS | квадратный корень | [op] a0 | [op] b1 | [op] b2 | [op] b3 |
_mm_rcp_ss | RCPSS | обратное значение | [op] a0 | a1 | a2 | a3 |
_mm_rcp_ps | RCPPS | обратное значение | [op] a0 | [op] b1 | [op] b2 | [op] b3 |
_mm_rsqrt_ss | RSQRTSS | обратное значение квадратного корня | [op] a0 | a1 | a2 | a3 |
_mm_rsqrt_ps | RSQRTPS | обратное значение квадратного корня | [op] a0 | [op] b1 | [op] b2 | [op] b3 |
_mm_min_ss | MINSS | минимум | [op](a0,b0) | a1 | a2 | a3 |
_mm_min_ps | MINPS | минимум | [op](a0,b0) | [op](a1,b1) | [op](a2,b2) | [op](a3,b3) |
_mm_max_ss | MAXSS | максимум | [op](a0,b0) | a1 | a2 | a3 |
_mm_max_ps | MAXPS | максимум | [op](a0,b0) | [op](a1,b1) | [op](a2,b2) | [op](a3,b3) |
Функции сравнения
Каждая встроенная функция сравнения выполняет сравнение операндов a и b. В векторной форме сравниваются четыре вещественных значения параметра a с четырьмя вещественными значениями параметра b, и возвращается 128-битная маска. В скалярной форме сравниваются младшие значения параметров, возвращается 32-битная маска, остальные три старших значения копируются из параметра a. Маска устанавливается в значение 0xffffffff для тех элементов, результат сравнения которых истина, и 0x0, где результат сравнения ложь.
Имя | Сравнение | Инструкция |
_mm_cmpeq_ss | равно | CMPEQSS |
_mm_cmpeq_ps | равно | CMPEQPS |
_mm_cmplt_ss | меньше | CMPLTSS |
_mm_cmplt_ps | меньше | CMPLTPS |
_mm_cmple_ss | меньше или равно | CMPLESS |
_mm_cmple_ps | меньше или равно | CMPLEPS |
_mm_cmpgt_ss | больше | CMPLTSS |
_mm_cmpgt_ps | больше | CMPLTPS |
_mm_cmpge_ss | больше или равно | CMPLESS |
_mm_cmpge_ps | больше или равно | CMPLEPS |
_mm_cmpneq_ss | не равно | CMPNEQSS |
_mm_cmpneq_ps | не равно | CMPNEQPS |
_mm_cmpnlt_ss | не меньше | CMPNLTSS |
_mm_cmpnlt_ps | не меньше | CMPNLTPS |
_mm_cmpnle_ss | не меньше или равно | CMPNLESS |
_mm_cmpnle_ps | не меньше или равно | CMPNLEPS |
_mm_cmpngt_ss | не больше | CMPNLTSS |
_mm_cmpngt_ps | не больше | CMPNLTPS |
_mm_cmpnge_ss | не больше или равно | CMPNLESS |
_mm_cmpnge_ps | не больше или равно | CMPNLEPS |
_mm_cmpord_ss | упорядочены | CMPORDSS |
_mm_cmpord_ps | упорядочены | CMPORDPS |
_mm_cmpunord_ss | неупорядочены | CMPUNORDSS |
_mm_cmpunord_ps | неупорядочены | CMPUNORDPS |
_mm_comieq_ss | равно | COMISS |
_mm_comilt_ss | меньше | COMISS |
_mm_comile_ss | меньше или равно | COMISS |
_mm_comigt_ss | больше | COMISS |
_mm_comige_ss | большеили равно | COMISS |
_mm_comineq_ss | не равно | COMISS |
_mm_ucomieq_ss | равно | UCOMISS |
_mm_ucomilt_ss | меньше | UCOMISS |
_mm_ucomile_ss | меньше или равно | UCOMISS |
_mm_ucomigt_ss | больше | UCOMISS |
_mm_ucomige_ss | больше или равно | UCOMISS |
_mm_ucomineq_ss | не равно | UCOMISS |
Операции преобразования типов
Имя функции | Операция | Инструкция |
_mm_cvtss_si32 | Преобразует младший float в 32-битное целое | CVTSS2SI |
_mm_cvtps_pi32 | Преобразует два младших float в два упакованных 32-битных целых | CVTPS2PI |
_mm_cvttss_si32 | Преобразует младший float в 32-битное целое, отбрасывая дробную часть | CVTTSS2SI |
_mm_cvttps_pi32 | Преобразует два младших float в два упакованных 32-битных целых, отбрасывая дробную часть | CVTTPS2PI |
_mm_cvtsi32_ss | Преобразует 32-битное целое в float | CVTSI2SS |
_mm_cvtpi32_ps | Преобразует два упакованных 32-битных целых в два младших float | CVTTPS2PI |
_mm_cvtpi16_ps | Преобразует четыре упакованных 16-битных целых в упакованные float | составная |
_mm_cvtpu16_ps | Преобразует четыре упакованных беззнаковых 16-битных целых в упакованные float | составная |
_mm_cvtpi8_ps | Преобразует четыре младших упакованных 8-битных целых в четыре упакованных float | составная |
_mm_cvtpu8_ps | Преобразует четыре младших упакованных беззнаковых 8-битных целых в четыре упакованных float | составная |
_mm_cvtpi32x2_ps | Преобразует две пары упакованных 32-битных целых в четыре упакованных float | составная |
_mm_cvtps_pi16 | Преобразует четыре упакованных float в четыре 16-битных целых | составная |
_mm_cvtps_pi8 | Преобразует четыре упакованных float в четыре младших 8-битных целых | составная |