В дополнение к FPU Intel предоставляет еще один механизм для работы с числами с плавающей точкой - расширения SSE или Streaming SIMD Extensions, которые призваны преодолеть недостатки стековой архитектуры FPU. Для вычислений SSE определяет 16 регистров XMM (от XMM0 до XMM15).
Набор инструкций SSE поддерживает два типа данных с плавающей точкой: 32-битные значения одинарной точности и 64-битные значения двойной точности. 80-битные значения расширенной точности не поддерживаются.
Для управления операциями SSE с плавающей точкой в SSE предназначен 32-битный регистр состояния и управления SSE MXCSR. Первые 16 бит имеют определенное значение:
0 (IE): Флаг исключения недопустимой операции. Устанавливается, если была попытка выполнить недопустимую операцию
1 (DE): Флаг исключения денормализации. Устанавливается, если результат операции - денормализованное значение
2 (ZE): Флаг нулевого исключения. Устанавливается, если была предпринята попытка деления на 0.
3 (OE): Флаг переполнения. Устанавливается, если было переполнение.
4 (UE): Флаг потери значимости (underflow). Устанавливается, если была потеря значимости
5 (PE): Флаг потери точности. Устанавливается, если была потеря точности.
6 (DAZ): Денормализованные значения равны 0. Если установлено, денормализованные значения обрабатываются как 0.
7 (IM): Неверная маска операции. Если установлено, исключения недопустимой операции игнорируются
8 (DM): Денормализованная маска. Если установлено, исключения денормализации игнорируются
9 (ZM): Маска деления на ноль. Если установлено, исключения деления на ноль игнорируются
10 (OM): Маска переполнения. Если установлено, исключения переполнения игнорируются
11 (UM): Маска потери значимости. Если установлено, исключения потери значимости игнорируются
12 (PM): Маска точности. Если установлено, исключения точности игнорируются
13-14: Управление округлением. может принимать ряд значений:
00: округление до ближайшего
01: округление до -бесконечности
10: округление до +бесконечности
11: округление до 0 (усечение)
15 (FTZ): Сброс до нуля. Когда установлено, все условия потери значимости устанавливают регистр в 0
Остальне биты 16-32 зарезервированы и в настоящее время не имеют значения.
Доступ к регистру SSE MXCSR осуществляется с помощью следующих двух инструкций:
ldmxcsr mem32 stmxcsr mem32
Инструкция ldmxcsr загружает регистр MXCSR из 32-битной переменной. Инструкция stmxcsr сохраняет текущее содержимое регистра MXCSR в 32-битную переменную. Как правило, данный регистр применяется для установки режима округления.
Для перемещения данных между регистрами XMM и переменными для чисел с плавающей точкой одинарной точности применяется инструкция movss, а для чисел с плавающей точкой двойной точности - инструкция movsd:
movss xmmn, mem32 movss mem32, xmmn movsd xmmn, mem64 movsd mem64, xmmn
Для максимальной производительности переменные, используемые в инструкции movss
, должны располагаться выравненны в памяти по двойному слову (4 бита),
а операнды инструкции movsd
— по адресу памяти, выровненному по четверному слову.
В дополнение SSE предоставляет инструкции movd и movq, которые позволяют перемещать данные между регистрами XMM и 32- и 64-битными регистрами общего назначения:
movd reg32, xmmn movd xmmn, reg32 movq reg64, xmmn movq xmmn, reg64
Стоит отметить, что эти команды не преобразуют значения с плавающей точкой в целые числа.
SSE предоставляет ряд инструкций для преобразования чисел с плавающей точкой в целые числа и обратно:
cvtsd2si: преобразует число с плавающей точкой двойной точности в 32- или 64-битное целое число. Использует текущий режим округления в MXCSR. Результат сохраняется в 32- или 64-битном регистре общего назначения.
cvtsd2si reg32/64, xmmn/mem64
cvtsd2ss: преобразует число с плавающей точкой двойной точности (в регистре XMM или переменной) в число с плавающей точкой одинарной точности и оставляет результат в первом операнде - регистре XMM. Использует текущий режим округления в MXCSR.
cvtsd2ss xmmn, xmmn/mem64
cvtsi2sd: преобразует 32- или 64-разрядное целое число в целочисленном регистре или переменной в число с плавающей точкой двойной точности, оставляя результат в регистре XMM.
cvtsi2sd xmmn, reg32/64/mem32/64
cvtsi2ss: преобразует 32- или 64-разрядное целое число в целочисленном регистре или переменной в число с плавающей точкой одинарной точности, оставляя результат в регистре XMM.
cvtsi2ss xmmn, reg32/64/mem32/64
cvtss2sd: преобразует значение с плавающей точкой одинарной точности в регистре XMM или переменной в значение двойной точности, оставляя результат в регистре XMM в первом операнде.
cvtss2sd xmmn, xmmn/mem32
cvtss2si: преобразует значение с плавающей точкой одинарной точности в регистре XMM или переменной в целое число и оставляет результат в 32- или 64-битном регистре общего назначения. Использует текущий режим округления в MXCSR.
cvtss2si reg32/64, xmmn/mem32
cvttsd2si: преобразует значение с плавающей точкой двойной точности в 32- или 64-битное целое число. Преобразование выполняется с использованием усечения (не использует биты управления округлением в MXCSR). Результат сохраняется в 32- или 64-битном регистре общего назначения.
cvttsd2si reg32/64, xmmn/mem64
cvttss2si: преобразует значение с плавающей точкой одинарной точности в 32- или 64-битное целое число. Преобразование выполняется с использованием усечения (не использует биты управления округлением в MXCSR). Результат сохраняется в 32- или 64-битном регистре общего назначения.
cvttss2si reg32/64, xmmn/mem32
Пример преобразования:
.data double1 real8 3.4 .code main proc movsd xmm0, double1 ; помещаем в xmm0 число double1 cvtsd2si rax, xmm0 ; из xmm0 преобразуем в целое число и помещаем в rax ret main endp end
В данном случае число 3.4, которое хранится в XMM0, преобразуется в целочисленное значение. И мы получим в регистре RAX число 3.