Каков самый быстрый способ очистки регистра (=0) в сборке MIPS?
Некоторые примеры:
xor $t0, $t0, $t0
and $t0, $t0, $0
move $t0, $0
li $t0, 0
add $t0, $0, $0
Какой самый эффективный?
Каков самый быстрый способ очистки регистра (=0) в сборке MIPS?
Некоторые примеры:
xor $t0, $t0, $t0
and $t0, $t0, $0
move $t0, $0
li $t0, 0
add $t0, $0, $0
Какой самый эффективный?
Во многих реализациях 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
могут быть самыми быстрыми, поскольку они сводят к минимуму ложные зависимости от других регистров.
memory_order_consume
). Таким образом, вы определенно хотите использовать $0
в качестве единственного регистра источника ввода, независимо от того, что вы с ним делаете. IDK, если какие-либо реализации MIPS с нарушением порядка распознают какие-либо конкретные идиомы обнуления и даже используют исполнительный блок (как это делают процессоры x86)
- person Peter Cordes; 24.10.2016
Кажется, я помню, что $0 был создан специально для этого случая, поэтому я ожидаю, что move $t0 $0
должен быть рекомендуемым способом очистки регистра. Но я не делал MIPS почти 10 лет...
Учитывая, что все эти инструкции занимают один конвейерный цикл, между ними не должно быть большой разницы.
Если таковые имеются, я ожидаю, что xor $t0, $t0, $t0
будет лучшим для скорости, потому что он не использует никаких других регистров, таким образом оставляя их свободными для других значений и потенциально уменьшая конфликт файлов регистров.
Метод xor также рассматривается как особая идиома на некоторых процессорах, что позволяет ему использовать еще меньше ресурсов (например, нет необходимости выполнять операцию XOR ALU.
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
будет наиболее эффективным.
mov x,y
обычно является синонимом or x,y,0
. Во всяком случае, так было на EE.
- person Crashworks; 27.10.2010
Вероятно, это зависит от того, какие еще инструкции будут в конвейере одновременно: когда регистр использовался в последний раз, когда он будет использоваться в следующий раз и какие внутренние блоки используются в данный момент.
Я не знаком со структурой конвейера любого конкретного процессора MIPS, но ваш компилятор должен быть таким, и я ожидаю, что он выберет то, что будет самым быстрым в данной последовательности кода.
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
$zero
в FPU с помощью инструкции ALU вместо загрузки из памяти? Или инструкции по передаче GP-›FP медленные?
- person Peter Cordes; 15.11.2019