Почему можно использовать регистр xzr вместо литерала 0 на ARMv8?
Я читал sve whitepaper из ARM и наткнулся на что-то, что показалось мне странным (в Примере без SVE):
mov x8, xzr
Я не знал, что это за регистр xzr
, поэтому я посмотрел его и нашел некоторое содержание из ARM, утверждающее, что во многих контекстах он был синонимом нуля.
Таким образом, похоже, что x8
инициализируется до нуля, что имеет смысл, потому что он выполняется непосредственно перед циклом, где x8
используется в качестве цикла счетчик.
Чего я не понимаю, так это почему не был использован литерал 0
вместо xzr
? Например:
mov x8, 0
Подводя итог, я задаюсь вопросом: почему здесь можно использовать регистр xzr
вместо литерала 0
?5 ответов:
Я думаю, что сравнение
mov x8, xzr
vsmov x8, #0
является чем-то вроде отвлекающего маневра.Как показывает ответ @old_timer, нет никакого усиления кодирования, и вполне вероятно (хотя, по общему признанию, я не проверял) небольшое или полное увеличение производительности конвейера.
То, что
Я думаю, что это важная характеристика, на которую оригинальный 'некоторый контент из ARM', упомянутый в OP, пренебрегает указать.xzr
дает нам, однако - в дополнение к фиктивному регистру согласно ответу @InfinitelyManic - это доступ к нулевому операнду без необходимости загружать и занимать реальный регистр. Это имеет двойное преимущество одного меньше инструкций, и еще один регистр, доступный для хранения "реальных" данных.Вот что я имею в виду под
mov x8, xzr
противmov x8, #0
быть отвлекающим маневром. Если мы обнуляемx8
с намерением затем изменить его, то использованиеxzr
или#0
довольно произвольно (хотя я бы предпочел#0
как более очевидное). Но если мы обнуляемx8
чисто для того, чтобы снабдить нулевым операндом последующую инструкцию, тогда нам было бы лучше использовать - где это разрешено -xzr
вместоx8
в качестве операнда в этой инструкции, а не обнулятьx8
вообще.
mov x8,xzr mov x8,#0 mov x8,0
Производит
0000000000000000 <.text>: 0: aa1f03e8 mov x8, xzr 4: d2800008 mov x8, #0x0 // #0 8: d2800008 mov x8, #0x0 // #0
Никакого реального удивления там не было, кроме того, что это позволило немедленно без знака фунта. Это не проблема размера инструкции (опять же неудивительно, что с x86,например,xor rax, rax дешевле, чем mov rax, 0), возможно, есть увеличение производительности конвейера (несмотря на распространенное мнение, что инструкции берут больше, чем один запуск часов, чтобы закончить).
Скорее всего, это личное предпочтение вещь у нас есть этот прохладный mips как всегда нулевой регистр вещь позволяет использовать его только для веселье.
Эти две инструкции должны быть идентичны - как с точки зрения эффекта, так и ожидаемой эффективности.
На самом деле они оба псевдонимы инструкций более общего назначения.
mov x8, 0
кодируется какorr x8, xzr, 0
Псевдонимы полезны, потому что они делают ASM более читаемым. Вторая кодировка демонстрирует, почему наличие нулевого регистра
mov x8, xzr
кодируется какorr x8, xzr, xzr
xzr
может быть полезным. Поскольку мы знаем, что xzr всегда равен нулю, мы можем повторно использоватьorr
инструкция дляmov
. Без негоmov
потребовало бы другой кодировки, и поэтому было бы потрачено впустую пространство кодировки.
Этот ответ не является "на четвереньках" Для OP.
XZR может использоваться для отбрасывания результатов; например, "ldr xzr, [sp], 16". См. GDB ниже
0x7fffffef40: 0x00000000 0x00000000 0x00400498 0x00000000 0x7fffffef50: 0x00000000 0x00000000 0x00000000 0x00000000 ldr x0,=0xdead (gdb) ldr x1,=0xc0de (gdb) stp x0, x1, [sp, #-16]! (gdb) x/8x $sp 0x7fffffef30: 0x0000dead 0x00000000 0x0000c0de 0x00000000 0x7fffffef40: 0x00000000 0x00000000 0x00400498 0x00000000 ldr xzr, [sp], #16 (gdb) x/8x $sp 0x7fffffef40: 0x00000000 0x00000000 0x00400498 0x00000000 0x7fffffef50: 0x00000000 0x00000000 0x00000000 0x00000000
Также помните, что в ARMv8 стек должен быть выровнен по четырем словам или SP mod 16 = 0. Таким образом, вы можете использовать XZR один из регистров пары "pushed" или "pop".
stp x1, xzr, [sp, #-16]! ldp x10, xzr, [sp], #16
TL; DR
Для загрузки 64-битного литерала в регистр требуется несколько команд, но только одна команда устанавливается в 0 с помощью zxr. Поэтому код короче и быстрее.
Чтобы переместить литерал в регистр, вы должны использовать инструкцию MOVL, смотрите это из ссылки arm:
Таким образом, загрузка литерала в регистр-это многоступенчатый процесс. Если вы просто хотите очистить реестр, то у них есть ярлык. zxr-это псевдо-регистр, который всегда считывает ноль, что является общим значением, которое вам понадобится, и перемещение регистра в регистр может быть сделано в одной инструкции.Псевдо-инструкция MOVL
Загрузите регистр либо с помощью:
A 32-bit or 64-bit immediate value. Any address.
MOVL генерирует либо две, либо четыре инструкции... мова, MOVK пара.
В сборке микрочипов они имеют схожую концепцию. Чтобы установить регистр в литерал, вы должны сделать что-то вроде:
MOVLW 10 (Move 10 to the working register) MOVWF 0x1234 (Move the working register to address 0x1234)
Но для установки в ноль у них есть инструкция:
CLRF 0x1234 (Set 0x1234 to zero)