В 32-битной версии у нас было 8 регистров общего назначения. С 64-битной версией количество удваивается, но, кажется, не зависит от самого 64-битного изменения.
Теперь, если регистры такие быстрые (нет доступа к памяти), почему их, естественно, не стало больше? Разве сборщики ЦП не должны загружать в ЦП как можно больше регистров? Каково логическое ограничение того, почему у нас есть только та сумма, которая у нас есть?
88
Ответы:
Есть много причин, по которым у вас не просто огромное количество регистров:
В наши дни у нас действительно много регистров - просто они явно не запрограммированы. У нас есть «переименование реестра». Хотя вы получаете доступ только к небольшому набору (8-32 регистров), на самом деле они поддерживаются гораздо большим набором (например, 64-256). Затем ЦП отслеживает видимость каждого регистра и размещает их в переименованном наборе. Например, вы можете загружать, изменять, а затем сохранять в регистре много раз подряд, и каждая из этих операций фактически выполняется независимо в зависимости от промахов в кеше и т. Д. В ARM:
Ядра Cortex A9 действительно переименовывают регистры, поэтому первая загрузка в «r0» фактически идет в переименованный виртуальный регистр - назовем его «v0». Загрузка, приращение и сохранение происходят на «v0». Между тем, мы также снова выполняем загрузку / изменение / сохранение в r0, но оно будет переименовано в «v1», потому что это полностью независимая последовательность с использованием r0. Допустим, загрузка с указателя в «r4» остановилась из-за промаха кеша. Ничего страшного - нам не нужно ждать, пока "r0" будет готов. Поскольку он переименован, мы можем запустить следующую последовательность с «v1» (также сопоставленным с r0) - и, возможно, это попадание в кеш, и мы только что получили огромный выигрыш в производительности.
Я думаю, что в наши дни x86 имеет гигантское количество переименованных регистров (приблизительное 256). Это означало бы иметь 8 бит умножить на 2 для каждой инструкции, чтобы просто сказать, что такое источник и место назначения. Это значительно увеличило бы количество проводов, необходимых для прохождения сердечника, и его размер. Таким образом, существует золотая середина между 16-32 регистрами, на которую согласились большинство разработчиков, и для нестандартных схем ЦП переименование регистров - способ смягчить ее.
Изменить : важность выполнения вне очереди и переименования реестра. Если у вас есть ООО, количество регистров не имеет большого значения, потому что они просто «временные теги» и переименовываются в гораздо больший набор виртуальных регистров. Вы не хотите, чтобы это число было слишком маленьким, потому что становится трудно писать небольшие последовательности кода. Это проблема для x86-32, потому что ограниченные 8 регистров означают, что множество временных файлов в конечном итоге проходит через стек, а ядру требуется дополнительная логика для пересылки операций чтения / записи в память. Если у вас нет ООО, вы обычно говорите о небольшом ядре, и в этом случае большой набор регистров дает низкое преимущество в соотношении цена / производительность.
Таким образом, существует естественная золотая середина для размера банка регистров, который составляет максимум около 32 регистров для большинства классов ЦП. x86-32 имеет 8 регистров и определенно слишком мал. В ARM было 16 регистров, и это хороший компромисс. 32 регистра - это немного многовато - вам не понадобятся последние 10 или около того.
Ничего из этого не касается дополнительных регистров, которые вы получаете для SSE и других векторных сопроцессоров с плавающей запятой. Это имеет смысл как дополнительный набор, потому что они работают независимо от целочисленного ядра и не увеличивают сложность процессора экспоненциально.
источник
Мы ли их больше
Поскольку почти каждая инструкция должна выбирать 1, 2 или 3 архитектурно видимых регистра, увеличение их количества приведет к увеличению размера кода на несколько бит для каждой инструкции и, таким образом, к снижению плотности кода. Это также увеличивает объем контекста, который должен быть сохранен как состояние потока и частично сохранен в записи активации функции . Эти операции происходят часто. Блокировки конвейера должны проверять табло для каждого регистра, и это имеет квадратичную временную и пространственную сложность. И, возможно, самая большая причина - просто совместимость с уже определенным набором инструкций.
Но оказывается, благодаря зарегистрировать переименование , мы действительно имеем много доступных регистров, и мы даже не нужно , чтобы спасти их. На самом деле у ЦП много наборов регистров, и он автоматически переключается между ними по мере выполнения вашего кода. Это делается исключительно для того, чтобы получить больше регистров.
Пример:
В архитектуре, которая имеет только r0-r7, следующий код может быть автоматически переписан ЦП как что-то вроде:
В этом случае r10 - это скрытый регистр, который временно заменяет r1. ЦП может сказать, что значение r1 больше не используется после первого сохранения. Это позволяет отложить первую загрузку (даже попадание в кеш-память на кристалле обычно занимает несколько циклов), не требуя задержки второй загрузки или второго хранилища.
источник
Они постоянно добавляют регистры, но часто привязаны к инструкциям специального назначения (например, SIMD, SSE2 и т. Д.) Или требуют компиляции под конкретную архитектуру ЦП, что снижает переносимость. Существующие инструкции часто работают с конкретными регистрами и не могли бы использовать преимущества других регистров, если бы они были доступны. Старый набор инструкций и все такое.
источник
Чтобы добавить сюда немного интересной информации, вы заметите, что наличие 8 регистров одинакового размера позволяет кодам операций поддерживать согласованность с шестнадцатеричной нотацией. Например, инструкция
push ax
имеет код операции 0x50 на x86 и увеличивается до 0x57 для последнего регистра di. Затем инструкцияpop ax
начинается с 0x58 и увеличивается до 0x5F,pop di
чтобы завершить первый base-16. Шестнадцатеричная последовательность поддерживается 8 регистрами на размер.источник