MIPS (любопытство) более быстрый способ очистки реестра?

Каков самый быстрый способ очистки регистра (=0) в сборке MIPS?

Некоторые примеры:

xor    $t0, $t0, $t0
and    $t0, $t0, $0
move   $t0, $0
li     $t0, 0
add    $t0, $0, $0

Какой самый эффективный?


person lois    schedule 26.10.2010    source источник


Ответы (6)


Во многих реализациях MIPS обе эти операции компилируются в одну и ту же инструкцию, потому что обычно «mov $a, $b» — это идиома для or $a, $b, $0, а li $r, x — сокращение для ori $r, $0, x:

move $t0, $0
li $t0, 0

и оба они будут выполняться на одном и том же конвейере, будучи архитектурно эквивалентными:

xor $t0, $t0, $t0
and $t0, $t0, $0

и в каждой реализации RISC, с которой я когда-либо работал, add находится в том же канале, что и xor/and/nor/etc.

По сути, все это зависит от реализации конкретного чипа, но все они должны быть с одним тактовым сигналом. Если микросхема вышла из строя, li или and x, $0, $0 могут быть самыми быстрыми, поскольку они сводят к минимуму ложные зависимости от других регистров.

person Crashworks    schedule 27.10.2010
comment
Если MIPS похож на ARM или PPC, для распространения архитектурно требуются инструкции зависимость от их входных регистров (по причинам, связанным с memory_order_consume). Таким образом, вы определенно хотите использовать $0 в качестве единственного регистра источника ввода, независимо от того, что вы с ним делаете. IDK, если какие-либо реализации MIPS с нарушением порядка распознают какие-либо конкретные идиомы обнуления и даже используют исполнительный блок (как это делают процессоры x86) - person Peter Cordes; 24.10.2016

Кажется, я помню, что $0 был создан специально для этого случая, поэтому я ожидаю, что move $t0 $0 должен быть рекомендуемым способом очистки регистра. Но я не делал MIPS почти 10 лет...

person Guillaume    schedule 27.10.2010

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

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

Метод xor также рассматривается как особая идиома на некоторых процессорах, что позволяет ему использовать еще меньше ресурсов (например, нет необходимости выполнять операцию XOR ALU.

person andrewmu    schedule 26.10.2010
comment
Разработчики ЦП оптимизируют ЦП x86 для идиомы xor-zeroing, потому что она имеет наименьший размер кода в кодировании переменной длины x86. Это, в свою очередь, сделало обнуление xor более эффективно, чем mov eax, 0, даже независимо от размера кода. Поскольку это не является фактором для MIPS, я бы не ожидал, что процессоры MIPS будут тратить транзисторы на обнаружение того, что оба операнда одинаковы для xor или sub. Я также ожидаю, что чтение $0 по крайней мере так же дешево, как чтение любого другого регистра. - person Peter Cordes; 24.10.2016

В большинстве реализаций архитектуры MIPS все они должны обеспечивать одинаковую производительность. Однако можно представить себе суперскалярную систему, которая могла бы выполнять несколько инструкций одновременно, если они используют отдельные внутренние блоки. У меня нет фактического примера системы MIPS, которая работает подобным образом, но именно так это происходит в системах PowerPC. Код операции xor $t0, $t0, $t0 будет выполняться на блоке «целочисленных вычислений» (поскольку это xor), а move $t0, $0 не будет использовать этот блок; концептуально последний может выполняться параллельно с другим кодом операции, выполняющим целочисленные вычисления.

Короче говоря, если вы обнаружите систему, в которой все перечисленные вами способы не одинаково эффективны, тогда я ожидаю, что метод move $t0, $0 будет наиболее эффективным.

person Thomas Pornin    schedule 27.10.2010
comment
Я думаю, что в большинстве реализаций mov также является целым числом — mov x,y обычно является синонимом or x,y,0. Во всяком случае, так было на EE. - person Crashworks; 27.10.2010
comment
Не знаком с MIPS, но инструкция по перемещению больше не используется? На x86 более длинные инструкции часто могут выполняться дольше официального количества тактов из-за проблем с памятью/конвейерной обработкой. Предпочтительны краткие инструкции... - person Brian Knoblauch; 27.10.2010
comment
@Brian Knoblauch Нет, весь смысл MIPS (и RISC в целом) в том, что каждая инструкция имеет одинаковую длину. - person Crashworks; 28.10.2010
comment
Я бы не сказал, что в этом весь смысл, но это действительно одно из преимуществ RISC-архитектуры (хотя оно становится немного менее выраженным с добавлением 16-битных подмножеств, таких как mips16e и Thumb). - person Igor Skochinsky; 28.10.2010

Вероятно, это зависит от того, какие еще инструкции будут в конвейере одновременно: когда регистр использовался в последний раз, когда он будет использоваться в следующий раз и какие внутренние блоки используются в данный момент.

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

person Andrew Aylett    schedule 27.10.2010
comment
Есть варианты, которые не зависят от старого значения регистра, так что нет, лучший выбор не зависит от окружающего кода. or $t1, $zero, $zero, вероятно, всегда так же хорош, как и любой другой выбор на любом MIPS. Вероятно, можно с уверенностью предположить, что суперскалярный MIPS может запускать addu или or на любом исполнительном устройстве, поэтому давление на серверный порт со стороны окружающего кода, вероятно, также не имеет значения. - person Peter Cordes; 15.11.2019

Вы можете просто использовать регистр $zero в качестве ссылки и записать его значение, равное 0 или 0b00000000, в регистр, который вы хотите очистить.

Если вы работаете с числами с плавающей запятой или двойными числами, вы можете просто объявить переменную с плавающей запятой и/или двойную в .data как 0.0 и записать ее в регистр, который вы хотите очистить, когда захотите.

Пример:

.data
     PI:       .float   3.14
     clear:    .float   0.0
.text
     main:
          lwc1 $f0, PI
          lwc1 $f0, clear

     li $v0, 10
     syscall
person Melqui Brito    schedule 15.11.2019
comment
Не было бы столь же или более эффективно передавать или преобразовывать $zero в FPU с помощью инструкции ALU вместо загрузки из памяти? Или инструкции по передаче GP-›FP медленные? - person Peter Cordes; 15.11.2019