Мне всегда было интересно, почему процессоры остановились на 32 регистрах. Это, безусловно, самая быстрая часть машины, почему бы просто не сделать процессоры большего размера с большим количеством регистров? Разве это не значит меньше идти в ОЗУ?
Мне всегда было интересно, почему процессоры остановились на 32 регистрах. Это, безусловно, самая быстрая часть машины, почему бы просто не сделать процессоры большего размера с большим количеством регистров? Разве это не значит меньше идти в ОЗУ?
Ответы:
Во-первых, не все процессорные архитектуры остановились на 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 ( √
Еще две причины ограничения количества регистров:
Большая часть кода имеет много обращений к памяти (30% - типичная цифра). Из этого, как правило, около 2 / 3rds являются доступами для чтения, а 1 / 3rds являются доступом для чтения. Это происходит не столько из-за нехватки регистров, сколько из-за доступа к массивам, доступа к переменным-членам объекта и т. Д.
Это ДОЛЖНО быть сделано в памяти (или кеше данных) из-за того, как создается C / C ++ (все, что вы можете получить, указатель должен иметь адрес, который потенциально должен храниться в памяти). Если компилятор может догадаться, что вы не будете произвольно писать в переменные с помощью сумасшедших трюков с косвенными указателями, он поместит их в регистры, и это прекрасно работает для переменных функций, но не для глобально доступных (как правило, всего, что исходит от malloc). ()) потому что по сути невозможно догадаться, как изменится глобальное состояние.
Из-за этого не так часто, что компилятор в любом случае может делать что-либо с более чем 16 общими регистрами использования. Вот почему все популярные архитекторы имеют столько (у ARM 16).
MIPS и другие RISC обычно имеют 32, потому что не так уж и сложно иметь такое количество регистров - стоимость достаточно низкая, поэтому это немного «почему бы и нет?». Более 32 в основном бесполезны и имеют недостаток в том, чтобы увеличить доступ к файлу регистров (каждое удвоение количества регистров потенциально добавляет дополнительный уровень мультиплексоров, который добавляет немного больше задержки ...). Это также в среднем делает инструкции немного длиннее - это означает, что при запуске программ, которые зависят от пропускной способности памяти команд, ваши дополнительные регистры на самом деле замедляют вас!
Если ваш процессор работает по порядку и не переименовывает регистры, и вы пытаетесь выполнить много операций за цикл (более 3), то в теории вам нужно больше регистров по мере увеличения числа операций за цикл. Вот почему у Itanium так много регистров! Но на практике, кроме числового кода с плавающей запятой или SIMD-ориентированного кода (в котором Itanium был действительно хорош), большая часть кода будет иметь много операций чтения / записи и перехода в памяти, что делает эту мечту о более чем 3 операциях за цикл невозможной (особенно в серверно-ориентированном программном обеспечении, таком как базы данных, компиляторы, выполнение языка высокого уровня, такое как javascript, эмуляция и т. д.). Это то, что затонул Itanium.
Все сводится к разнице между вычислениями и выполнением!
Кто вам скажет, что процессор всегда имеет 32 регистра? x86 имеет 8, ARM 32-разрядный и x86_64 имеют 16, IA-64 имеет 128 и многие другие числа. Вы можете посмотреть здесь . Даже MIPS, PPC или любые архитектуры, которые имеют 32 регистра общего назначения в наборе команд, их число намного больше 32, поскольку всегда есть регистры флагов (если они есть), регистры управления ... не включая переименованные регистры и аппаратные регистры
У всего есть своя цена. Чем больше количество регистров, тем больше работы вы выполняете при переключении задач, тем больше места вам нужно в кодировке команд. Если у вас меньше регистров, вам не нужно много хранить и восстанавливать при вызове и возврате из функций или переключении задач с компромиссом отсутствия регистров в некотором вычислительном коде
Более того, чем больше файл реестра, тем дороже и сложнее он будет. SRAM является самой быстрой и самой дорогой оперативной памятью, поэтому она используется только в кэш-памяти процессора. Но это все еще намного дешевле и занимает меньше места, чем файл реестра с той же емкостью.
Например, типичный процессор Intel имеет «официально» 16 целочисленных и 16 векторных регистров. Но на самом деле их гораздо больше: процессор использует «переименование регистров». Если у вас есть инструкция reg3 = reg1 + reg2, у вас возникнет проблема, если другая инструкция, использующая reg3, еще не завершена - вы не сможете выполнить новую инструкцию, если она перезаписывает reg3 до того, как она была прочитана предыдущей инструкцией.
Поэтому существует около 160 или около того реальных регистров. Таким образом, простая инструкция выше заменена на «regX = reg1 + reg2, и помните, что regX содержит reg3». Без переименования регистров выполнение из-за ордера было бы абсолютно мертвым в воде.
Я не инженер-электрик, но я думаю, что другой возможностью по причине ограничения количества регистров является маршрутизация. Количество арифметических единиц ограничено, и они должны иметь возможность принимать входные данные из каждого регистра и выводить их в каждый регистр. Это особенно верно, когда у вас есть конвейерные программы, которые могут выполнять много команд за цикл.
Простая версия этого будет иметь сложность , делая увеличение количества регистров не масштабируемым, или иначе требуя перепроектирования маршрутизации к чему-то намного более сложному, чтобы маршрутизировать все с лучшей сложностью.
Я получил представление об этом ответе после просмотра некоторых выступлений Ивана Годара на процессоре Mill. Часть нововведения процессора Mill состоит в том, что вы не можете выводить данные в произвольные регистры - все выходы помещаются в стек регистров или «пояс», что, таким образом, уменьшает проблемы маршрутизации, потому что вы всегда знаете, куда пойдут выходные данные. Обратите внимание, что у них все еще есть проблема маршрутизации для получения входных регистров к арифметическим единицам.
См . Архитектура процессора Mill - пояс (2 из 9) для постановки задачи и решения Милля.