Перейти к содержанию
    

Ассемблерная оптимизация маленького куска (порядка 10-15 инструкций)

Примерно получается (если считать, что входное слово, 12-битная маска, адреса таблиц уже загружены,регистры сохранены, и таблиц всего 3 по 12/12/8 бит):

Не понимаю - почему Вы выбрали 12/12/8, а не 11/11/10? Ведь первый вариант требует 16896 байт таблиц, в то время как 2-ой - только 10240. :wacko:

 

ldr r1, [r4, r1]; загружаем младшие 12 бит (r4 был предварительно загружен и будет ещё многократно использоваться)

ldr r2, [r5, r2, LSR #12]; загружаем средние 12 бит (r5 был предварительно загружен и будет ещё многократно использоваться)

ldr r3, [r6, r0, LSR #24]; загружаем старшие 8 бит (r6 был предварительно загружен и будет ещё многократно использоваться)

Забываете, что читаете не байты, а слова. Надо сдвинуть все индексы влево на 1 бит. Так что кол-во команд будет на 1 больше. И команды не LDR, а LDRH.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В моём случае не принципиально 10 килобайт или 16, а дискреты в 4 бита мне удобнее для пересчёта таблиц из их первоначального вида (где было 8 таблиц по 16 4-битных значений в каждой)

 

Насчёт не байты, а слова - да, лопухнулся, написал как было раньше, когда было 4 однобайтовых таблицы. Сдвигать нужно на 1 бит индексы у двух таблиц, третья осталась однобайтовой.

Только вот не понял, откуда ещё 1 команда, вроде же достаточно поменять на код вида

ldr r1, [r4, r1, LSL#1]; загружаем младшие 12 бит (r4 был предварительно загружен и будет ещё многократно использоваться)
ldr r2, [r5, r2, LSR #11]; загружаем средние 12 бит (r5 был предварительно загружен и будет ещё многократно использоваться)
ldr r3, [r6, r0, LSR #24]; загружаем старшие 8 бит (r6 был предварительно загружен и будет ещё многократно использоваться)

Изменено пользователем Himmler

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Вы упорно пишете LDR, хотя Вам надо грузить 16-битные слова :twak:

Доп. команда добавляется если использовать 11/11/10 рассечение (нужно маскировать и сдвинуть старшие 10бит, а это не получится сделать сразу в LDRH). Ок, тогда оставим 12/12/8.

Тогда получим:

;исх. данные:
;R0 - аргумент;
;R7 = 0x1FFE
AND R1, R7, R0, LSL #1;получаем индекс*2 в первой таблице
AND R2, R7, R0, LSR #12-1;получаем индекс*2 во второй таблице
LDRH R1, [R4, R1];загружаем младшие 12 бит (r4 был предварительно загружен и будет ещё многократно использоваться)
LDRH R2, [R5, R2];загружаем средние 12 бит (r5 был предварительно загружен и будет ещё многократно использоваться)
LDRB R3, [R6, R0, LSR #24];загружаем старшие 8 бит (r6 был предварительно загружен и будет ещё многократно использоваться)
ADD R1, R1, R2, LSL #12;собираем 3 куска в одно 32-битное слово
ADD R1, R3, LSL #24

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Опять же согласен, вгружать 32-битные слова неправильно.

 

То есть на данный момент 7 тактов. Больше нигде и ничего не срезать ?

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

LDRB R3, [R6, R0, LSR #24] - это наверное из другой вселенной.

В скобках адрес, при этом модификации подвергается последний регистор в записи,

и двигать (умножать) его можно исключительно в лево,

и число для модификации от единицы до трёх,

и чтение байта с такой модификацией - теряет смысл, ибо глюканёт на несоответствии объявленных границ выравнивания переменных и зарегистрированной командой.

 

В целом трешь и угар, выдыхайте:).

Изменено пользователем AVI-crak

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

К сожалению прямо сейчас у меня железяки и полноценного ide под рукой нету, смогу только завтра проверить.

 

Но ARMSim#.191, onlinedisassembler.com и ARM instruction evaluator прекрасно переварили такой код, взаимно понимая друг друга и отлично ассемблируя/дизассемблируя результаты друг друга.

В частности LDRB R3, [R6, R0, LSR #24] (машинный код E7D63C20) делает именно то, что задумывалось.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Извиняюсь за задержку, сегодня проверил код, погонял на разных входных данных - работает именно так, как нужно

;R0 - используется другим куском кода
;R1 - используется другим куском кода
;R2 - здесь храним кусок (12 бит)
:R3 - здесь храним второй кусок (12 бит)
;R4 = in_data
;R5  = table_0_pointer = 0x4000
;R6  = table_1_pointer = 0x6000
;R7  = table_2_pointer = 0x3F00
;R8 = mask (0x1FFE)
;R9-R14 - используется другим куском кода


AND R2, R8, R4, LSL #1
AND R3, R8, R4, LSR #11
LDRH R2, [R5, R2]
LDRH R3, [R6, R3]
LDRB R4, [R7, R4, LSR #24]
ADD R2, R2, R3, LSL #12
ADD R2, R2, R4, LSL #24

 

Поглядел на весь код в целом - было бы очень хорошо сэкономить два регистра. Ну или хотя бы один.

Предположительно, это можно как-нибудь сделать, не храня все три адреса в R5, R6 и R7, а храня один их них, а два других -вычисляя на лету. Но тут я столкнулся с тем, что LDRH не хочет делать сдвиги и суммирования, как это делают LDR и LDRB.

Можно ли тут как-нибудь извернуться ? Разумеется, не увеличивая число инструкций.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Во-первых блокировка при загрузке байт/слов составляет не один такт, а два.

Во-вторых все сдвиги, прилепленные к командам, совсем не бесплатные, и тоже добавляют блокировку на использование сдвигаемого регистра на один такт.

 

Возможно, есть что-то ещё, и в результате приведённый мной выше код работает правильно, но в два раза дольше, чем я ожидал.

 

Единственное, что сразу пришло на ум и чуть-чуть ускорило выполнение - перенос одной команды загрузки слова на пораньше. Но особой погоды это не сделало.

 

Поэтому актуален следующий вопрос:

 

Как можно изменить код (в том числе с добавлением команд и расходованием доп. регистров), чтобы уменьшить именно количество тактов при выполнении ?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Это не сюрпризы, всё документировано (DDI0439B, DDI0210B). Частично этим и объясняется, что x86 уделывала ARM когда-то.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Во-первых блокировка при загрузке байт/слов составляет не один такт, а два.

Во-вторых все сдвиги, прилепленные к командам, совсем не бесплатные, и тоже добавляют блокировку на использование сдвигаемого регистра на один такт.

 

Возможно, есть что-то ещё, и в результате приведённый мной выше код работает правильно, но в два раза дольше, чем я ожидал.

 

Единственное, что сразу пришло на ум и чуть-чуть ускорило выполнение - перенос одной команды загрузки слова на пораньше. Но особой погоды это не сделало.

 

Поэтому актуален следующий вопрос:

 

Как можно изменить код (в том числе с добавлением команд и расходованием доп. регистров), чтобы уменьшить именно количество тактов при выполнении ?

а развернуть цикл, и конвертировать паралельно 2 числа, может както уменьшить простои?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

 

Это наверное ваша команда чтения из памяти виновата LDRB R3, [R6, R0, LSR #24]

У старенького arm926 - ядро ARM7TDMI, и его команды имеют чёткое описание

http://www.gaw.ru/html.cgi/txt/doc/micros/...tmi/insruct.htm

 

Формат чтения памяти : [Rn, +/-Rm, LSR #5bit_shift_imm] , но в реальности LSR-LSL - это пятый бит смещения, а нулевой бит просто не участвует в операции - и того 3 бита смещения. То-есть как у всех ARM чипов.

 

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

У старенького arm926 - ядро ARM7TDMI

Это что-то новенькое :cranky:

 

и его команды имеют чёткое описание

Да. См. тут.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Это что-то новенькое :cranky:

 

 

Да. См. тут.

 

А тут значится ложная инфа ? https://www.arm.com/products/processors/cla...arm9/arm926.php

 

И тут. https://www.arm.com/products/processors/cla...arm9/arm926.php, заявлена двоичная совместимость с ядром ARM7TDMI.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А тут значится ложная инфа ? https://www.arm.com/products/processors/cla...arm9/arm926.php

 

И тут. https://www.arm.com/products/processors/cla...arm9/arm926.php, заявлена двоичная совместимость с ядром ARM7TDMI.

Нет там никакой ложной информации. ARM926 и ARM7TDMI - это разные процессоры. Двоичная совместимость не предполагает одинаковые времена выполнения инструкций (хотя случайно может и совпадать местами). Точно так же, как Cortex-M4 двоично совместим с Cortex-M3, но время выполнения некоторых инструкций отличается.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

А тут значится ложная инфа ? https://www.arm.com/products/processors/cla...arm9/arm926.php

И тут. https://www.arm.com/products/processors/cla...arm9/arm926.php, заявлена двоичная совместимость с ядром ARM7TDMI.

двоичная совместимость это несколько не то.

компьютер что у вас на столе сейчас стоит тогда тоже можно 80386 обозвать, но от процессора тридцатилетней давности он всё-таки несколько отличается.

соответственно и у ARMv5 по сравнению с ARMv4 отличия тоже есть.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

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

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...