Я думаю, что я ищу ответ на вопрос о пустяках. Я пытаюсь понять, почему архитектура MIPS использует явное «нулевое» значение в регистре, когда вы можете достичь того же, просто XOR'и любой регистр против самого себя. Можно сказать, что операция уже сделана для вас; тем не менее, я не могу себе представить ситуацию, когда вы использовали бы много «нулевых» значений. Я читаю оригинальные статьи Хеннесси, и это просто присваивает ноль на самом деле без какого-либо реального оправдания.
Существует ли логическая причина иметь жестко запрограммированное двоичное присвоение нуля?
обновление: в 8k исполняемого файла из xc32-gcc для ядра MIPS в PIC32MZ у меня есть один экземпляр "ноль".
add t3,t1,zero
фактический ответ: я присудил награду человеку, который имел информацию о MIPS и кодах условий. Ответ на самом деле лежит в архитектуре MIPS для условий. Хотя изначально я не хотел выделять на это время, я рассмотрел архитектуру для opensparc , MIPS-V и OpenPOWER (этот документ был внутренним), и вот краткие выводы. Регистр R0 необходим для сравнения по веткам из-за архитектуры конвейера.
- целочисленное сравнение с нулем и ответвлением (bgez, bgtz, blez, bltz)
- целочисленное сравнение двух регистров и ветви (beq, bne)
- целочисленное сравнение двух регистров и trap (teq, tge, tlt, tne)
- регистр сравнения целых чисел и немедленный и trap (teqi, tgei, tlti, tnei)
Это просто сводится к тому, как аппаратное обеспечение выглядит в реализации. Из руководства MIPS-V на странице 68 есть ссылка, на которую нет ссылок:
Условные ветви были разработаны так, чтобы включать операции арифметического сравнения между двумя регистрами (как это также делается в PA-RISC и Xtensa ISA), а не использовать коды условий (x86, ARM, SPARC, PowerPC) или сравнивать только один регистр с нулем ( Альфа, MIPS) или два регистра только для равенства (MIPS). Эта конструкция была мотивирована наблюдением, что объединенная команда сравнения и ветвления ts в обычный конвейер позволяет избежать дополнительного состояния кода условия или использования временного регистра и уменьшает размер статического кода и динамическую трассировку выборки команд. Другой момент заключается в том, что для сравнения с нулем требуется нетривиальная задержка контура (особенно после перехода к статической логике в сложных процессах), и поэтому она почти такая же дорогая, как и арифметическая величина. Другое преимущество объединенной команды сравнения и ветвления состоит в том, что ответвления наблюдаются раньше в потоке внешних команд и поэтому могут быть предсказаны ранее. Возможно, есть преимущество для схемы с кодами условий в том случае, когда можно использовать несколько ветвей на основе одних и тех же кодов условий, но мы считаем, что этот случай является относительно редким.
Документ MIPS-V не попадает в автора цитируемого раздела. Я благодарю всех за их время и внимание.
источник
Ответы:
Нулевой регистр на процессорах RISC полезен по двум причинам:
Это полезная константа
В зависимости от ограничений ISA, вы не можете использовать литерал в кодировке некоторых инструкций, но вы можете быть уверены, что можете использовать его
r0
для получения 0.Может использоваться для синтеза других инструкций
Это, пожалуй, самый важный момент. Как разработчик ISA, вы можете обменять регистр общего назначения на нулевой регистр, чтобы иметь возможность синтезировать другие полезные инструкции. Синтезировать инструкции хорошо, потому что, имея меньше фактических инструкций, вам нужно меньше битов для кодирования операции в коде операции, что освобождает пространство в пространстве кодирования команд. Вы можете использовать это пространство, чтобы иметь, например, большие смещения адресов и / или литералы.
Семантика нулевого регистра аналогична
/dev/zero
системам * nix: все записанное в него отбрасывается, и вы всегда читаете обратно 0.Давайте рассмотрим несколько примеров того, как мы можем создавать псевдоинструкции с помощью
r0
нулевого регистра:Дело о MIPS
Я более внимательно посмотрел на набор инструкций MIPS. Есть несколько псевдоинструкций, которые используют
$zero
; они в основном используются для филиалов. Вот несколько примеров того, что я нашел:Что касается того, почему вы нашли только один экземпляр
$zero
регистра в вашей разборке, возможно, это ваш дизассемблер, который достаточно умен, чтобы преобразовать известные последовательности команд в их эквивалентную псевдоинструкцию.Нулевой регистр действительно полезен?
Что ж, очевидно, ARM считает наличие нулевого регистра достаточно полезным, что в их (несколько) новом ядре ARMv8-A, которое реализует AArch64, теперь есть нулевой регистр в 64-битном режиме; раньше не было нулевого регистра. (Регистр немного особенный, хотя, в некоторых контекстах кодирования это нулевой регистр, в других он вместо этого обозначает указатель стека )
источник
slt
,slti
,sltu
).Большинство реализаций ARM / POWER / SPARC имеют скрытый регистр RAZ
Вы можете подумать, что ARM32, SPARC и т. Д. Не имеют регистра 0, но на самом деле они есть! На уровне микроархитектуры большинство инженеров-проектировщиков ЦП добавляют регистр 0, который может быть невидим для программного обеспечения (нулевой регистр ARM невидим), и используют этот нулевой регистр для упрощения декодирования команд.
Рассмотрим типичный современный дизайн ARM32, который имеет программный невидимый регистр, скажем, R16, подключенный к 0. Рассмотрим загрузку ARM32, во многих случаях инструкция загрузки ARM32 попадает в одну из этих форм (некоторое время игнорируйте предварительную индексацию, чтобы сохранить обсуждение простым ) ...
Внутри процессора это декодирует в общий
перед входом в стадию выдачи, где читаются регистры. Обратите внимание, что rx представляет регистр для обратной записи обновленного адреса. Вот несколько примеров декодирования:
На уровне цепи все три нагрузки фактически являются одной и той же внутренней инструкцией, и простой способ получить такую ортогональность состоит в создании наземного регистра R16. Поскольку R16 всегда заземлен, эти инструкции, естественно, правильно декодируются без какой-либо дополнительной логики. Отображение класса инструкций в единый внутренний формат очень помогает в суперскалярных реализациях, поскольку уменьшает сложность логики.
Другая причина - упрощенный способ выбросить записи. Инструкции можно отключить, просто установив регистр назначения и отметив R16. Нет необходимости создавать какой-либо другой управляющий сигнал для отключения обратной записи и т. Д.
Большинство реализаций процессоров, независимо от архитектуры, заканчиваются моделью регистра RAZ на ранней стадии разработки. Конвейер MIPS, по сути, начинается с точки, которая в других архитектурах будет в несколько этапов.
MIPS сделал правильный выбор
Таким образом, регистр «чтение как ноль» является почти обязательным в любой современной реализации процессора, и MIPS, делающий его видимым для программного обеспечения, безусловно, является плюсом, учитывая, как он оптимизирует внутреннюю логику декодирования. Разработчикам процессоров MIPS не нужно добавлять дополнительный регистр RAZ, поскольку $ 0 уже на земле. Поскольку RAZ доступен для ассемблера, для MIPS доступно множество инструкций psuedo, и это можно рассматривать как передачу части логики декодирования самому ассемблеру вместо создания выделенных форматов для каждого типа команд, чтобы скрыть регистр RAZ из программного обеспечения. как с другими архитектурами. Регистр RAZ - хорошая идея, и поэтому ARMv8 скопировал его.
Если бы ARM32 имел регистр $ 0, логика декодирования стала бы проще, а архитектура была бы намного лучше с точки зрения скорости, площади и мощности. Например, из трех представленных выше версий LDR потребуются только два формата. Точно так же нет необходимости резервировать логику декодирования для команд MOV и MVN. Кроме того, CMP / CMN / TST / TEQ станет избыточным. Также не было бы необходимости проводить различие между коротким (MUL) и длинным умножением (UMULL / SMULL), поскольку короткое умножение можно рассматривать как длинное умножение с высоким регистром, установленным в $ 0 и т. Д.
Поскольку MIPS изначально разрабатывался небольшой командой, важна была простота проектирования, и поэтому $ 0 был явно выбран в духе RISC. ARM32 сохраняет множество традиционных функций CISC на архитектурном уровне.
источник
Отказ от ответственности: я действительно не знаю ассемблера MIPS, но регистр 0-значений не уникален для этой архитектуры, и я думаю, что он используется так же, как и в других известных мне архитектурах RISC.
XOR для регистра для получения 0 будет стоить вам одну инструкцию, в то время как использование предопределенного 0-значного регистра не будет.
Например,
mov RX, RY
инструкция часто реализуется какadd RX, RY, R0
. Без 0-значного регистра вам придетсяxor RZ, RZ
каждый раз, когда вы хотите использоватьmov
.Другим примером является
cmp
инструкция и ее варианты (например, «сравнить и перейти», «сравнить и переместить» и т. Д.), Гдеcmp RX, R0
используется для проверки на отрицательные числа.источник
MOV Rx,Ry
какAND Rx,Ry,Ry
?mov RX, Imm
илиmov RX, mem[RY]
если ваш набор команд поддерживает только одно непосредственное значение и один доступ к памяти для каждой инструкции.mov
плохой пример; Вы могли бы реализовать это с непосредственным 0 вместо нулевого регистра. напримерori dst, src, 0
. Но да, вам понадобится код операции для mov-немедленного, чтобы зарегистрироваться, если у вас его нетaddiu $dst, $zero, 1234
, например,lui
для младших 16 бит вместо верхних 16. И вы не можете использоватьnor
илиsub
создать один операнд, а не / neg ,Привязка нескольких выводов к земле в конце вашего регистрационного банка стоит дешево (дешевле, чем сделать его полноценным регистром).
Выполнение фактического xor требует немного энергии и времени, чтобы переключить ворота и затем сохранить их в реестре, зачем платить эту стоимость, если существующее значение 0 может быть легко доступно.
Современные процессоры также имеют (скрытый) регистр с 0 значениями, которые они могут использовать в результате выполнения
xor eax eax
инструкции через переименование регистров.источник
R0
заключается не в заземлении нескольких проводов, а в том, что вы должны зарезервировать для него код в каждой инструкции, которая имеет дело с регистрами.std::memory_order_consume
) требуют XOR для распространения зависимости.lui
но не смещено влево на 16. Таким образом, вы все равно можете поместить небольшое число в регистр с одной инструкцией. Разрешение только нуля с ложной зависимостью было бы безумием. (Обычный MIPS создает ненулевые значения с помощьюaddiu $dst, $zero, 1234
илиori
, поэтому ваш аргумент «затраты на электроэнергию» не работает. Если вы хотите избежать запуска ALU, вы должны добавить код операции для mov-немедленного для регистрации вместо программного обеспечения ADD или OR немедленное с нуля.)