Почему процессор имеет 32 регистра?

52

Мне всегда было интересно, почему процессоры остановились на 32 регистрах. Это, безусловно, самая быстрая часть машины, почему бы просто не сделать процессоры большего размера с большим количеством регистров? Разве это не значит меньше идти в ОЗУ?

Мэтт Капоне
источник
2
Я предполагаю, что после определенного момента все ваши локальные переменные помещаются в регистры. Фактические данные, с которыми вы работаете, в любом случае, вероятно, слишком велики
Никлас Б.
14
Снижение отдачи. Ясно, что регистры «дороже» (в разных смыслах), чем ОЗУ, иначе у нас было бы 8 ГБ регистров.
Дэвид Ричерби
5
Одна из причин, по которой он так быстр, в том, что их не так много.
stackErr
5
Существует разница между тем, сколько регистров имеет процессор, и тем, сколько вы можете использовать одновременно.
Турбьерн Равн Андерсен
Процессоры и графические процессоры скрывают задержки в основном за счет кэшей и многопоточности соответственно. Таким образом, у процессоров мало регистров, а у графических процессоров десятки тысяч в регистрах. См. Мой обзорный документ о файле регистра GPU, в котором обсуждаются все эти компромиссы и факторы.
user984260

Ответы:

82

Во-первых, не все процессорные архитектуры остановились на 32 регистрах. Почти все архитектуры RISC, которые имеют 32 регистра, представленных в наборе команд, на самом деле имеют 32 регистра целых чисел и еще 32 регистра с плавающей запятой (т.е. 64). (Плавающая точка «add» использует регистры, отличные от целочисленного «add».) Архитектура SPARC имеет окна регистров, В SPARC вы можете получить доступ только к 32 целочисленным регистрам одновременно, но регистры действуют как стек, и вы можете выдвигать и извлекать новые регистры 16 одновременно. Архитектура Itanium от HP / Intel имела 128 целочисленных и 128 регистров с плавающей запятой, представленных в наборе команд. Современные графические процессоры от NVidia, AMD, Intel, ARM и Imagination Technologies представляют огромное количество регистров в своих файлах регистров. (Я знаю, что это верно для архитектур NVidia и Intel, я не очень хорошо знаком с наборами команд AMD, ARM и Imagination, но я думаю, что файлы реестра там тоже большие.)

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

Есть две причины, по которым может быть сложно дополнительно увеличить количество регистров, представленных в наборе команд. Во-первых, вы должны быть в состоянии указать идентификаторы регистра в каждой инструкции. Для 32 регистров требуется 5-битный спецификатор регистра, поэтому 3-адресные инструкции (общие для архитектур RISC) тратят 15 из 32 битов инструкций только для указания регистров. Если вы увеличите это значение до 6 или 7 бит, то у вас будет меньше места для указания кодов операций и констант. Графические процессоры и Itanium имеют гораздо большие инструкции. Более крупные инструкции обходятся дорого: вам нужно использовать больше памяти для инструкций, поэтому ваше поведение в кэше инструкций менее идеальное.

Вторая причина - время доступа. Чем больше вы делаете память, тем медленнее для доступа к данным из нее. (С точки зрения базовой физики: данные хранятся в двухмерном пространстве, поэтому, если вы храните битов, среднее расстояние до определенного бита равно .) Файл регистра - это просто небольшая многопортовая память, и одно из ограничений при ее увеличении заключается в том, что в конечном итоге вам придется начинать синхронизировать свою машину медленнее, чтобы вместить больший файл регистра. Обычно с точки зрения общей производительности это потеря. O ( nO(n)

Блуждающая логика
источник
1
Я бы упомянул 256 FPR SPARC64 VIIIfx и 32 дополнительных GPR без окон, что достигается добавлением инструкции Set XAR, которая предоставляет 13 битов для каждой следующей или двух инструкций. Он был нацелен на HPC, поэтому число регистров более понятно. Я также был бы соблазн объяснить некоторые из компромиссов и методов, связанных с большим количеством регистров; но вы показали мудрость, чтобы избежать более изнурительного (и даже не исчерпывающего) ответа.
Пол А. Клейтон,
2
Возможно, стоит добавить небольшую выгоду от уменьшения количества регистров для кода «общего назначения», хотя найти значимые измерения не так просто. Я думаю, что Митч Алсуп упомянул на comp.arch, что расширение x86 до 32 регистров, а не 16, увеличило бы производительность примерно на 3% по сравнению с (ISTR) 10-15% для выбранного расширения регистра от 8 до 16. Даже для ISA хранилища нагрузки переход на 64, вероятно, дает мало преимуществ (по крайней мере, для текущего кода GP). (Кстати, графические процессоры часто совместно используют регистры между потоками: например, один поток с 250, оставляя 16 полностью закрытыми для других потоков.)
Пол А. Клейтон,
Интересно видеть, что управление средой (следовательно, альфа-преобразование), часто связанное с языками высокого уровня, фактически используется на уровне регистров.
Бабу
@ PaulA.Clayton Я всегда думал, что IA-64 - это архитектура с наибольшим количеством регистров ISA
phuclv
@ LưuVĩnhPhúc SPARC64 VIIIfx был специфичным для HPC. К вашему сведению, Am29k (выпущенный в 1987-8 гг. ) Имел 64 глобальных и 128 оконных GPR, что является большим количеством GPR, чем Itanium (который имеет 8 регистров ветвления и регистр счетчика циклов, функция которого была бы в GPR в некоторых других ISA).
Пол А. Клейтон,
16

Еще две причины ограничения количества регистров:

  • Небольшой выигрыш, ожидаемый: процессор, такой как текущие модели Intel / AMD x64, имеет 32 КБ и более кэш-памяти L1-D, а доступ к кэш-памяти L1 обычно занимает только один тактовый цикл (по сравнению с приблизительно сотней тактовых циклов для полной одной ОЗУ). доступ). Таким образом, мало что можно получить от наличия большего количества данных в регистрах по сравнению с наличием данных в кэше L1
  • Дополнительные вычислительные затраты. Наличие большего количества регистров создает дополнительную нагрузку, которая может фактически замедлить работу компьютера:
    • В многозадачных средах переключатель задач обычно должен сохранять содержимое всех регистров процесса, которые оставлены в памяти, и должен загружать те из процесса, который должен быть введен. Чем больше регистров у вас есть, тем дольше это занимает.
    • Точно так же в архитектурах без окон регистров вызовы каскадных функций используют один и тот же набор регистров. Таким образом, функция A, вызывающая функцию B, использует тот же набор регистров, что и сама B. Следовательно, B должен сохранить содержимое всех используемых им регистров (которые все еще содержат значения A) и должен записать их обратно перед возвратом (в некоторых соглашениях о вызовах задача A - сохранить содержимое своего регистра перед вызовом B, но накладные расходы аналогичны). Чем больше регистров у вас есть, тем дольше выполняется сохранение, и, следовательно, становится дороже вызов функции.
Роберт Буххольц
источник
Как это работает для кеша L1, чтобы у нас не было такой же проблемы, как для регистров?
Бабу
4
На высокопроизводительных процессорах задержка L1 Dcache чаще всего составляет 3 или 4 цикла (включая генерацию адреса), например, у Intel Haswell имеет 4-тактовую задержку (отсутствие задержки в регистре зависимости от данных также легче скрыть в конвейере). Dcache также имеет тенденцию поддерживать меньше обращений за цикл (например, 2 чтения, 1 запись для Haswell), чем файл регистра (например, 4 чтения, 6 запись для Alpha 21264, который реплицировал файл, 2 файла с 4 чтениями быстрее, чем 1 с 8).
Пол А. Клэйтон
@ PaulA.Clayton: Если кэш-память L1 имеет задержку 3-4 цикла, это может свидетельствовать о некоторой выгоде, например, иметь несколько наборов из 64 слов памяти с одним циклом и собственным адресным пространством из 64 слов, и выделенные инструкции «загрузить / сохранить напрямую», особенно если был способ выдвинуть все ненулевые значения, за которым следовало слово, говорящее о том, какие слова были ненулевыми, а затем способ вернуть их обратно (обнуление любых регистров, которые не выдвинуты) , Многие методы содержат от 16 до 60 слов локальных переменных, поэтому сокращение времени доступа для них с 3-4 циклов до одного может показаться полезным.
суперкат
@supercat Различные стековые (и глобальные / TLS [например, Knapsack]) идеи кеширования были представлены в научных статьях, а также такие механизмы, как буфер сигнатур ( PDF ). Фактическое использование, не так много (кажется). Это становится болтливым (так что, вероятно, должно закончиться или пойти в другое место).
Пол А. Клейтон
4

Большая часть кода имеет много обращений к памяти (30% - типичная цифра). Из этого, как правило, около 2 / 3rds являются доступами для чтения, а 1 / 3rds являются доступом для чтения. Это происходит не столько из-за нехватки регистров, сколько из-за доступа к массивам, доступа к переменным-членам объекта и т. Д.

Это ДОЛЖНО быть сделано в памяти (или кеше данных) из-за того, как создается C / C ++ (все, что вы можете получить, указатель должен иметь адрес, который потенциально должен храниться в памяти). Если компилятор может догадаться, что вы не будете произвольно писать в переменные с помощью сумасшедших трюков с косвенными указателями, он поместит их в регистры, и это прекрасно работает для переменных функций, но не для глобально доступных (как правило, всего, что исходит от malloc). ()) потому что по сути невозможно догадаться, как изменится глобальное состояние.

Из-за этого не так часто, что компилятор в любом случае может делать что-либо с более чем 16 общими регистрами использования. Вот почему все популярные архитекторы имеют столько (у ARM 16).

MIPS и другие RISC обычно имеют 32, потому что не так уж и сложно иметь такое количество регистров - стоимость достаточно низкая, поэтому это немного «почему бы и нет?». Более 32 в основном бесполезны и имеют недостаток в том, чтобы увеличить доступ к файлу регистров (каждое удвоение количества регистров потенциально добавляет дополнительный уровень мультиплексоров, который добавляет немного больше задержки ...). Это также в среднем делает инструкции немного длиннее - это означает, что при запуске программ, которые зависят от пропускной способности памяти команд, ваши дополнительные регистры на самом деле замедляют вас!

Если ваш процессор работает по порядку и не переименовывает регистры, и вы пытаетесь выполнить много операций за цикл (более 3), то в теории вам нужно больше регистров по мере увеличения числа операций за цикл. Вот почему у Itanium так много регистров! Но на практике, кроме числового кода с плавающей запятой или SIMD-ориентированного кода (в котором Itanium был действительно хорош), большая часть кода будет иметь много операций чтения / записи и перехода в памяти, что делает эту мечту о более чем 3 операциях за цикл невозможной (особенно в серверно-ориентированном программном обеспечении, таком как базы данных, компиляторы, выполнение языка высокого уровня, такое как javascript, эмуляция и т. д.). Это то, что затонул Itanium.

Все сводится к разнице между вычислениями и выполнением!

Хьюберт Ламонтань
источник
2

Кто вам скажет, что процессор всегда имеет 32 регистра? x86 имеет 8, ARM 32-разрядный и x86_64 имеют 16, IA-64 имеет 128 и многие другие числа. Вы можете посмотреть здесь . Даже MIPS, PPC или любые архитектуры, которые имеют 32 регистра общего назначения в наборе команд, их число намного больше 32, поскольку всегда есть регистры флагов (если они есть), регистры управления ... не включая переименованные регистры и аппаратные регистры

У всего есть своя цена. Чем больше количество регистров, тем больше работы вы выполняете при переключении задач, тем больше места вам нужно в кодировке команд. Если у вас меньше регистров, вам не нужно много хранить и восстанавливать при вызове и возврате из функций или переключении задач с компромиссом отсутствия регистров в некотором вычислительном коде

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

phuclv
источник
2

Например, типичный процессор Intel имеет «официально» 16 целочисленных и 16 векторных регистров. Но на самом деле их гораздо больше: процессор использует «переименование регистров». Если у вас есть инструкция reg3 = reg1 + reg2, у вас возникнет проблема, если другая инструкция, использующая reg3, еще не завершена - вы не сможете выполнить новую инструкцию, если она перезаписывает reg3 до того, как она была прочитана предыдущей инструкцией.

Поэтому существует около 160 или около того реальных регистров. Таким образом, простая инструкция выше заменена на «regX = reg1 + reg2, и помните, что regX содержит reg3». Без переименования регистров выполнение из-за ордера было бы абсолютно мертвым в воде.

gnasher729
источник
1

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

Простая версия этого будет иметь сложность , делая увеличение количества регистров не масштабируемым, или иначе требуя перепроектирования маршрутизации к чему-то намного более сложному, чтобы маршрутизировать все с лучшей сложностью.O(n2)

Я получил представление об этом ответе после просмотра некоторых выступлений Ивана Годара на процессоре Mill. Часть нововведения процессора Mill состоит в том, что вы не можете выводить данные в произвольные регистры - все выходы помещаются в стек регистров или «пояс», что, таким образом, уменьшает проблемы маршрутизации, потому что вы всегда знаете, куда пойдут выходные данные. Обратите внимание, что у них все еще есть проблема маршрутизации для получения входных регистров к арифметическим единицам.

См . Архитектура процессора Mill - пояс (2 из 9) для постановки задачи и решения Милля.

Реал Слав
источник
«Они должны иметь возможность принимать входные данные из каждого регистра и выводить их в каждый регистр». - Я ожидаю, что это обычно реализуется с шиной, для каждого регистра не требуется отдельное соединение с ALU.
user253751
1
@immibis: Если вы хотите переместить данные за 300 пикосекунд, то автобус этого не сделает. И если вы хотите переместить много данных (например, выполнить три инструкции с двумя операндами и по одному результату в одном и том же цикле), то шина абсолютно, абсолютно не будет работать.
gnasher729
0

Что касается MIPS ISA, Hennessy and Patterson, Computer Organisation and Design, 4-е издание, с. 176, отвечает на этот конкретный вопрос напрямую:

Меньше быстрее. Стремление к скорости является причиной того, что MIPS имеет 32 регистра, а не многие другие.

Olsonist
источник