Pull to refresh

Comments 15

Спасибо, интересная вещь.

Интересно, arm_dsp_library пользует ли данную инструкцию? Функции копирования там есть, но вот оптимизирует ли они свой код этой инструкцией или отдают на откуп компилятору, не ясно до конца.

Замечание: одна и та же команда не может использоваться и для копирования, и для работы со стеком, потому что в случае стека команда push должна делать не инкремент, а декремент, и писать регистры в обратном порядке.

Команда LDM имеет модификатор для управления порядком действий:
ldmia (increment after)
ldmib (increment before)
ldmda (decrement after)
ldmdb (decrement before)

Регистры пишутся в одинаковом порядке (IIRC).

В ARM стек можно сделать в любом направлении и даже в обоих одновременно:
в режиме jazelle есть два стека — Java и нативный стек, которые растут в противоположные стороны.

ещё лучше, вы можете всё восстановить и вернуться за один раз!
pop {fp, pc}

Надо понимать, что за один раз — это как минимум 3 цикла тут + сброс конвейера.

А что по времени выполнения таких инструкций?

или проще говоря, количеству всех задействованных регистров
AArch64 ISA спроектирована так, чтобы быть эффективной на больших OoO процессорах.

пришлось пойти на компромисс и удвоить количество регистров до 32-х.

Компромисс — странное слово применительно к удвоению регистров не меняя при этом размера инструкции.
Отказ от условного выполнения инструкций (не только не полезного, но и вредного для OoO) позволил сильно увеличить пространство опкодов и удвоить количество регистров.

Таким образом, вместо ARM64 появились LDP и STP

Множественная загрузка так же плохо ложится на OoO движок (микрокод, неравномерное использование rob/rename, возможно даже блокировка ld queue/st queue).
На PowerPC аналогичный lmw также реализован в микрокоде и не рекомендуется к использованию вообще никогда (даже в in-order процессорах).

Даже старые Cortex-ы могут выполнять чтение и запись одновременно благодаря наличию двух блоков LD/ST.
Копирование рекомендуется осуществлять интерливом:
    LDRD r3,r4,[r1,#0] 
    STRD r3,r4,[r0,#0] 
    LDRD r3,r4,[r1,#8] 
    STRD r3,r4,[r0,#8]

LDRD это почти что аналог LDP для 32-битного режима.

Таким образом LDM хорош только на микроконтроллерах или на старых ARM-ах.
Команда зависает в конвейере на 1 такт больше чем всё остальное
LDRD R0, R1, [R2, #const.]!
Сразу за ней запрещено использовать команду перехода (в любом варианте), а так-же любой другой команды с любым из используемых регистров. Нужна команда прослойка. Всё дело в том что R2 должен сначала измениться.
LDR R0, [R1], #const
Тут требуется две команды до использования регистров или перехода.
Словом, программировать на асме для арм — можно только в самых исключительных случаях — когда уже нет иного выхода.
Сразу за ней запрещено использовать команду перехода (в любом варианте), а так-же любой другой команды с любым из используемых регистров.

Это где же такое написано? И что по-вашему будет? Big badaboom?

По крайней мере в доке по A-профайлу ничего такого нет.
developer.arm.com/documentation/ddi0406/b/Application-Level-Architecture/Instruction-Details/Alphabetical-list-of-instructions/LDRD--register-?lang=en

В псевдокоде показано когда результат невалидный — к примеру когда регистром приёмником является регистр адреса, при включении режима апдейта адреса.

Всё дело в том что R2 должен сначала измениться.

developer.arm.com/documentation/ddi0290/g/cycle-timings-and-interlock-behavior/load-and-store-doubleword-instructions

The updated base register has a result latency of one. For back-to-back load/store instructions with base write back, the updated base is available to the following load/store instruction with a result latency of 0.

Тут требуется две команды до использования регистров или перехода.

Это называется load-to-use latency. Никто вас не заставляет впихивать команды в пузыри если не хотите. К переходу это вообще не имеет никакого отношения, если конечно код не прыгает через R0. Выполнение инструкций после перехода начинается ещё до того как завершится выполнение вашего load-а.
На OoO процессоре вообще не нужно затыкать пузыри. Как показано на моём примере выше — группировка load-load | store-store менее эффективна чем back-to-back. OoO движок их выполнит когда нужно.
В реальности конечно мы генерим код по разные таргеты, например (A57-A78)+(A53-A55).

Словом, программировать на асме для арм — можно только в самых исключительных случаях — когда уже нет иного выхода.

Программировать на ARM легко и приятно. Если программируете in-order процессор, то неплохо бы понимать что такое темп и что такое латентность. И ARM тут ничем не отличается от остальных.
И что по-вашему будет?

Регистр R0 не успеет обновиться из внешней памяти.
Это не сложно проверить.
Процессор работает согласно спецификации.
В каком документе описаны ваши «находки»?

Регистр R0 не успеет обновиться из внешней памяти.

С чего бы ему не успеть? При доступе к регистру, содержимое которого ещё не готово, на in-order процессоре будет столл.
Процессоры без отслеживания зависимостей бывают, например первые MIPS (Microprocessor without. Interlocked. Pipeline. Stages), но ARM не из их числа.

Чтение данных из внешней памяти, не находящехся в кэше — это не 1 и не 2, а сотни тактов.

Это не сложно проверить.

Давайте проверим :)

badaboom test
        .text
        .global _start
        .arch armv7a
_start:
        
        ldr r3,=result
        ldr r2,=testdata

        mov r0,#0x30
        mov r1,#0x30
        ldrd r0,r1,[r2,#8]! //34 
        strb r0, [r3,#0]
        strb r1, [r3,#1]

        mov r0,#0x30
        ldr r0,[r2],#4 //3
        b 1f
1:      strb r0,[r3,#2]

// show results
        mov r0,#0
        ldr r1,=text
        ldr r2,=textlen  
        mov r7,#4
        swi #0

        mov r0,#0
        mov r7,#1
        swi #0
 
        .data
text:   .ascii "result is "
result: .ascii "XXX\n"
textlen = . - text

testdata: .word 0x31,0x32,0x33,0x34
           




Осилите собрать?
as test.S
ld a.out -o test
./test

Какой по вашему мнению будет результат?

Обратите внимание на «опасный» бранч после ldr, чего по вашим словам делать запрещено!
Регистр R0 не успеет обновиться из внешней памяти.
Это не сложно проверить.

Не верю…
Была бы хорошей командой, но вызывает исключение при обращении к памяти с адресами не кратными 4-м. Это, конечно, портит жизнь разработчикам компиляторов.
Sign up to leave a comment.

Articles

Change theme settings