x86, как и почти любой другой «нормальный» процессор, для которого вы, возможно, изучите сборку, является «регистрирующей машиной» . Существуют и другие способы проектирования чего-либо, что вы можете программировать (например, машина Тьюринга, которая движется по логической «ленте» в памяти), но регистрационные машины оказались в основном единственным способом достижения высокой производительности.
Поскольку x86 был разработан для использования регистров, вы не можете полностью избежать их, даже если бы вы хотели и не заботились о производительности.
Текущие процессоры x86 могут читать / записывать гораздо больше регистров за такт, чем ячейки памяти.
Например, Intel Skylake может выполнять две загрузки и одно хранилище из / в свой 32-килобайтный ассоциативный L1D-кэш 32 кбайт за цикл (в лучшем случае), но может читать более 10 регистров за такт и записывать 3 или 4 (плюс EFLAGS) .
Создание кэша L1D с таким количеством портов чтения / записи, как файл регистра , будет непомерно дорогим (по количеству транзисторов / площади и потребляемой мощности), особенно если вы хотите сохранить его таким большим, как он является. Вероятно, просто физически невозможно создать что-то, что может использовать память, как x86 использует регистры с той же производительностью.
Кроме того, запись регистра и последующее его чтение имеют практически нулевую задержку, поскольку ЦП обнаруживает это и перенаправляет результат непосредственно с выхода одного исполнительного устройства на вход другого, минуя этап обратной записи. (См. https://en.wikipedia.org/wiki/Classic_RISC_pipeline#Solution_A._Bypassing).
Эти соединения для пересылки результатов между исполнительными блоками называются «обходной сетью» или «сетью пересылки», и для ЦП это гораздо проще сделать для конструкции регистра, чем если бы все приходилось идти в память и обратно. ЦПУ должен только проверять номер регистра из 3–5 бит вместо 32-битного или 64-битного адреса, чтобы обнаружить случаи, когда вывод одной инструкции необходим сразу как ввод для другой операции. (И эти регистрационные номера жестко запрограммированы в машинном коде, поэтому они доступны сразу.)
Как уже упоминалось, 3 или 4 бита для адресации регистра делают формат машинного кода намного более компактным, чем если бы каждая инструкция имела абсолютные адреса.
См. Также https://en.wikipedia.org/wiki/Memory_hierarchy: Вы можете думать о регистрах как о небольшом быстром фиксированном размере памяти, отделенной от основной памяти, где поддерживается только прямая абсолютная адресация. (Вы не можете «проиндексировать» регистр: если в одном регистре задано целое число N
, вы не можете получить содержимое N
-го регистра с одним insn.)
Регистры также являются частными для одного ядра ЦП, поэтому неупорядоченное выполнение может делать с ними все, что захочет. С памятью нужно беспокоиться о том, в каком порядке вещи видны другим ядрам процессора.
Наличие фиксированного количества регистров является частью того, что позволяет процессорам делать переименование регистров для выполнения вне очереди. Наличие номера регистра, доступного сразу же после декодирования инструкции, также облегчает эту задачу: никогда не выполняется чтение или запись в неизвестный регистр.
См. Почему Мулсс занимает всего 3 цикла в Haswell, в отличие от таблиц инструкций Агнера? для объяснения переименования регистров и конкретного примера (более поздние правки к вопросу / более поздним частям моего ответа) показывает ускорение от развертывания с несколькими аккумуляторами, чтобы скрыть задержку FMA, даже если он многократно использует один и тот же архитектурный регистр).
Буфер хранилища с пересылкой хранилища в основном дает вам «переименование памяти». Сохранение / перезагрузка в ячейку памяти не зависит от предыдущих хранилищ и загружается в эту ячейку из этого ядра.
Повторные вызовы функций с соглашением о вызовах стековых аргументов и / или возвращением значения по ссылке - это случаи, когда одни и те же байты стековой памяти могут многократно использоваться повторно.
Сохранение / перезагрузка секунд может выполняться, даже если первое хранилище все еще ожидает ввода. (Я проверял это на Skylake, но IDK, если я когда-нибудь опубликовал результаты в ответе.)