Можем ли мы сохранить число с плавающей запятой в обычном регистре? - PullRequest
1 голос
/ 11 апреля 2019

Как я понимаю, числа с плавающей запятой хранятся в XMM регистрах, а не в регистрах общего назначения, таких как eax, поэтому я провел эксперимент:

float a = 5;

в этом случае a сохраняется как 1084227584 в регистре XMM. Вот сборочная версия:

.text
        .global _start
.LCO:
        .long 1084227584
_start:
        mov .LCO, %eax
        movss .LCO, %xmm0

Выполнение вышеуказанной сборки и ее отладка с использованием gdb показывает, что значение в eax будет 1084227584, однако значение в ymm0 равно 5.

Вот мои вопросы:

1 - Что особенного в регистрах XMM? кроме инструкций SIMD, они являются единственным типом регистров для хранения чисел с плавающей запятой?

почему я не могу установить те же биты в обычном регистре?

2 - всегда ли значения float и double хранятся как числа с плавающей запятой?

Можем ли мы хранить их как fixed point в C или сборке?

Ответы [ 2 ]

6 голосов
/ 11 апреля 2019

однако значение в ymm0 равно 5.

битовый шаблон в ymm0 равен 1084227584. Поплавок интерпретация этого числа равна 5.0.

Но вы можете print /x $xmm0.v4_int32 увидеть шестнадцатеричное представление битов в xmm0.


Что такого особенного в регистрах XMM? кроме инструкций SIMD, они являются единственными типами регистров для хранения с плавающей запятой?

Нет, в asm все просто байты.

Некоторые компиляторы используют целочисленный регистр для копирования числа с плавающей запятой или двойного числа из одной ячейки памяти в другую, если на ней не выполняется никаких вычислений. (Целочисленные инструкции часто меньше.) Например, clang сделает это: https://godbolt.org/z/76EWMY

void copy(float *d, float *s) {   *d = *s; }

# clang8.0 -O3 targeting x86-64 System V
copy:                                   # @copy
    mov     eax, dword ptr [rsi]
    mov     dword ptr [rdi], eax
    ret

Регистры XMM / YMM / ZMM являются специальными, поскольку они являются единственными регистрами, для которых инструкции FP ALU существуют для (игнорируя x87, который используется только для 80-битных long double в x86-64) .

addsd xmm0, xmm1 (добавить скалярное двойное число) не имеет эквивалента для целочисленных регистров.

Обычно данные FP и целочисленные данные не очень смешиваются, поэтому предоставление целого отдельного набора архитектурных регистров дает больше места для большего количества данных в регистрах. (Учитывая те же ограничения кодирования команд, это выбор между 16 FP + 16 GP integer против 16 унифицированных регистров, а не против 32 унифицированных регистров).

Кроме того, основное микроархитектурное преимущество отдельного файла регистров состоит в том, что он может быть физически близок к ALU FP, а файл целочисленных регистров может быть физически близко к ALU целого числа. Подробнее см. . Существует ли какая-либо архитектура, использующая одно и то же пространство регистров для скалярных целочисленных операций и операций с плавающей запятой?


Значения float и double всегда сохраняются как числа с плавающей запятой? мы никогда не сможем хранить их как фиксированные точки в C или сборке?

x86-компиляторы используют float = двоичный код IEEE75432 https://en.wikipedia.org/wiki/Single-precision_floating-point_format. (и double = двоичный код IEEE754). Это указано как часть ABI.

Внутренне правило «как будто» позволяет компилятору делать все, что он хочет, при условии, что конечный результат идентичен. (Или с -ffast-math, чтобы сделать вид, что математика FP ассоциативна, и предположить, что NaN / Inf невозможны.)

Компиляторы не могут просто случайно выбрать другое представление объекта для некоторого float, на которое могут смотреть другие отдельно скомпилированные функции.

Могут быть редкие случаи для локальных пользователей, которые никогда не будут видны другим функциям, когда "человеческий компилятор" (asm для написания от руки для реализации C) может доказать, что фиксированная точка безопасна. Или, более вероятно, что значения float были точными целыми числами, достаточно маленькими, чтобы double не округлял их, поэтому ваша фиксированная точка могла вырождаться в целое число (за исключением, может быть, последнего шага).

Но было бы редко узнать столько о возможных значениях, если бы не было возможности делать постоянное распространение и оптимизировать все подряд. Вот почему я говорю, что человек должен быть вовлечен, чтобы доказать вещи, которые компилятор не узнает.


Я думаю, что теоретически у вас может быть реализация C, в которой использует фиксированную точку float или double. ISO C накладывает очень небольшие ограничения на то, что float и double на самом деле.

Но limits.h константы типа FLT_RADIX и DBL_MAX_EXP имеют взаимодействия, которые могут не иметь смысла для формата с фиксированной запятой, который имеет постоянное расстояние между каждым представимым значением, вместо того, чтобы быть намного ближе вместе около 0 и намного дальше друг от друга для большого числа. (Погрешность округления 0,5 мяча относительно абсолютной величины вместо абсолютной.)

Тем не менее, большинство программ на самом деле не делают вещи, которые сломались бы, если бы пределы "мантиссы" и экспоненты не соответствовали тому, что вы ожидаете для DBL_MIN и DBL_MAX.

Еще одна интересная возможность - сделать float и double на основе формата Posit (аналогично традиционной плавающей запятой, но с кодировкой экспоненты переменной длины. https://www.johndcook.com/blog/2018/04/11/anatomy-of-a-posit-number/ https://posithub.org/index).


Современное оборудование, особенно процессоры Intel, имеет очень хорошую поддержку IEEE float / double, поэтому фиксированная точка часто не является победой. Есть несколько хороших SIMD-инструкций для 16-битной фиксированнойоднако, как и умножение только на верхнюю половину, и даже pmulhrsw, который выполняет округление с фиксированной запятой.

Но общее 32-разрядное целочисленное умножение имеет худшую пропускную способность, чем упакованноеfloat умножение. (Поскольку для SIMD ALU, оптимизированных для числа с плавающей запятой / двойного числа, требуется только 24x24-битное значение и множители на 32 бита векторного элемента. Современные процессоры Intel выполняют целочисленное умножение и сдвиг на исполнительных блоках FMA с 2 мопами на тактовую пропускную способность.)

2 голосов
/ 11 апреля 2019

это единственный тип регистров для хранения чисел с плавающей запятой?

Нет.В 8087-совместимом FPU имеются 80-битные регистры с плавающей точкой (fp0 - fp7), которые должны присутствовать в большинстве современных процессоров.

Большинство 32-битных программ используют эти регистры.

Можем ли мы сохранить число с плавающей запятой в обычном регистре [целое число * ?

Да.30 лет назад многие ПК содержали процессор без 80x87 FPU, поэтому регистров fp0 - fp7 не было.Процессоры с регистрами XMM появились даже позже.

Сегодня мы наблюдаем похожую ситуацию в мобильных устройствах.

Что такого особенного в регистрах XMM?

Использование 80x87 FPU кажется более сложным, чем использование регистров XMM.Кроме того, я не уверен, разрешено ли использование 80x87 в 64-битных программах в каждой операционной системе.

Если вы храните значение с плавающей запятой в целочисленном регистре (например, eax), вынет никаких инструкций, выполняющих арифметику: на процессорах x86 нет инструкции для умножения или сложения значений с плавающей запятой, которые хранятся в целочисленных регистрах.

В случае процессоров без FPU выдолжны делать эмуляцию с плавающей точкой.Это означает, что вам нужно выполнить одну операцию с плавающей запятой, выполнив несколько целочисленных операций - так же, как вы сделали бы это с бумагой и карандашом.

Однако, если вы хотите сохранить только значение с плавающей запятой, вы можетеконечно также используйте регистр целых чисел.То же самое верно для копирования значения или проверки, если два значения равны и аналогичные операции.

Можем ли мы сохранить их как фиксированные точки в C или сборке?

Фиксированная точка часто используется при использовании процессоров, которые не имеют FPU.

Например, при использовании 8- или 16-битных процессоров, которые все еще используются в автомобильной промышленности, бытовых устройствах или периферийных устройствах ПК.

Однако я сомневаюсь, что есть компиляторы C, которые автоматически переводят ключевое слово "float" в фиксированную точку.

...