[Программирование] LDM. Моя любимая инструкция ARM (перевод)

Автор Сообщение
news_bot ®

Стаж: 6 лет 9 месяцев
Сообщений: 27286

Создавать темы news_bot ® написал(а)
21-Окт-2020 16:30

LDM — или load multiple — моя любимая инструкция в ассемблере для ARM. Вот почему.
Во-первых, что она делает. Вот пример:
ldm r4, {r0, r1, r2, r3}

Здесь она принимает базовый регистр (в данном случае r4) и набор регистров (в данном случае {r0, r1, r2, r3}). Загружает последовательные слова из адреса в базовом регистре в регистры из набора. Действие инструкции можно продемонстрировать с помощью такого C-подобного псевдокода:
r0 = r4[0];
r1 = r4[1];
r2 = r4[2];
r3 = r4[3];

Немало заданий для одной инструкции! Именно поэтому она называется load multiple.
Нотация набора также допускает диапазоны. Мы можем переписать предыдущий пример следующим образом:
ldm r4, {r0-r3}

В наборе разрешены все 16 регистров ARM. Итак, законно следующее:
ldm r0, {r0, r1, r2, r3, r4, r5, r6, r7, r8, r9, r10, r11, r12, r13, r14, r15}

В 32-битной инструкции набор регистров кодируется как 16-битная маска. Вот упрощённая кодировка исходного примера:
Упрощённое кодирование инструкции LDM

Такая инструкция идеально подходит для архитектуры load-store, такой как ARM, где основной рабочий процесс выглядит так:
  • загрузить множество значений из памяти в регистры,
  • выполнить операции исключительно с регистрами,
  • сохранить результаты из регистров обратно в память.

Противоположностью LDM находится STM — store multiple.
Копирование блоков
С помощью этих двух инструкций можно быстро копировать большие блоки памяти. Вы можете скопировать восемь слов (или 32 байта!) памяти всего двумя инструкциями:
ldm r0, {r4-r11}
stm r1, {r4-r11}

У LDM и STM также есть варианты автоинкремента (обозначаемые знаком “!”), где базовый регистр увеличивается на количество загруженных/сохранённых слов, так что можно копировать в быстром цикле:
ldm r0!, {r4-r11}
stm r1!, {r4-r11}

Реализация стеков
В ARM инструкция POP — это просто псевдоним для LDM с указателем стека (и автоинкрементом). Она выглядит и работает точно так же:
ldm sp!, {r0-r3}
pop {r0-r3}

А инструкция PUSH — это псевдоним для варианта STM (STMDB).
Вы можете делать push и pop, копируя регистры в большом объёме в стек и из него за один раз. А если заменить SP другим регистром, то сможете реализовать эффективные стеки в других областях памяти. Например, вы можете реализовать теневой стек в куче.
Сохранение регистров
Вы боитесь использовать регистры, сохранённые вызовом (call-preserved), потому что их требуется сохранить, а в любом случае можно использовать слот стека? Это больше не проблема, потому что можно за один раз сохранить все call-preserved регистры, которые вы хотите использовать:
push {r4-r11}

Пролог и эпилог
В ARM первые четыре аргумента, обратный адрес (LR) и указатель кадра (FP) передаются в регистрах. Вот почему особенно важно иметь эффективные пролог и эпилог. К счастью, вы можете сохранить FP и LR за один раз, используя довольно стандартный пролог ARM:
push {fp, lr}

А потом восстановить их и вернуться (для эпилога):
pop {fp, lr}
bx lr

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

Тут значение обратного адреса (LR) вставляется в регистр счётчика программ (PC), так что не нужен явный возврат!
Это достаточно хорошо само по себе, но можно одновременно отправить некоторые аргументы в стек (например, если их адрес занят):
push {r0-r3, fp, lr}

Или можно сохранить FP и LR и одновременно выделить некоторое пространство в стеке:
push {r0-r3, fp, lr}

В этом случае мы пушим r0-r3 не для их значения, а чтобы продвинуть указатель стека на четыре слова.
ARM64
Подозреваю, когда пришло время разработать 64-битную версию набора команд ARM, пришлось пойти на компромисс и удвоить количество регистров до 32-х. Помню, в какой-то статье говорилось, что это изменение улучшает производительность примерно на 6% по всем направлениям. С 32-мя регистрами больше невозможно закодировать битовую маску всех регистров в 32-битную длинную инструкцию. Таким образом, вместо ARM64 появились LDP и STP: load pair и store pair, духовные преемники LDM и STM.
Этот пост изначально начинался как тред в твиттере.
===========
Источник:
habr.com
===========

===========
Автор оригинала: Vladimir Keleshev
===========
Похожие новости: Теги для поиска: #_programmirovanie (Программирование), #_arm, #_arm64, #_ldm, #_stm, #_assembler (ассемблер), #_arhitektura_loadstore (архитектура load-store), #_tenevoj_stek (теневой стек), #_ldp, #_stp, #_programmirovanie (
Программирование
)
Профиль  ЛС 
Показать сообщения:     

Вы не можете начинать темы
Вы не можете отвечать на сообщения
Вы не можете редактировать свои сообщения
Вы не можете удалять свои сообщения
Вы не можете голосовать в опросах
Вы не можете прикреплять файлы к сообщениям
Вы не можете скачивать файлы

Текущее время: 22-Ноя 15:27
Часовой пояс: UTC + 5