|
Проблема с условием, m = m+I|P == I ? m : 0; |
|
|
|
Aug 25 2018, 09:23
|
Местный
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264
|
Цитата(jcxz @ Aug 25 2018, 10:59) Загляните как-нить в листинг Cortex-M3/4 кода и сравните команды LDRB и LDRSB например. Поймёте почему. Для этого имхо и ввели дополнительный чекбокс в IAR "signed/unsigned char". Сходу не получилось заставить компилятор сгенерировать LDRSB... Использую armcc в составе Keil. Оптимизация 0. Галка "Plain Char is Signed" сброшена. Код Код volatile signed char a = 10; volatile signed char b = 20; volatile signed char c;
int main(void) { c = a - b; while(1); } формирует следующий листинг Код 0x080002E0 4805 LDR r0,[pc,#20] 0x080002E2 7800 LDRB r0,[r0,#0x00]; загрузили a 0x080002E4 4905 LDR r1,[pc,#20] 0x080002E6 7809 LDRB r1,[r1,#0x00]; загрузили b 0x080002E8 1A40 SUBS r0,r0,r1 ; вычли 0x080002EA B240 SXTB r0,r0 ; ИМХО, лишнее, т.к. SUBS работает 32-битными числами 0x080002EC 4904 LDR r1,[pc,#16] 0x080002EE 7008 STRB r0,[r1,#0x00]; загружаем результат в переменную c В случае, если переменные объявить без спецификатора signed (то есть с unsigned) то листинг тот же самый, но без SXTB С оптимизацией -O3 для signed/unsigned листинг одинаковый: Код 0x0800028C 4803 LDR r0,[pc,#12] 0x0800028E 7801 LDRB r1,[r0,#0x00] 0x08000290 7842 LDRB r2,[r0,#0x01] 0x08000292 1A89 SUBS r1,r1,r2 0x08000294 7081 STRB r1,[r0,#0x02]
Сообщение отредактировал Arlleex - Aug 25 2018, 09:33
|
|
|
|
|
Aug 25 2018, 09:59
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(Arlleex @ Aug 25 2018, 12:23) Сходу не получилось заставить компилятор сгенерировать LDRSB... Использую armcc в составе Keil. Оптимизация 0. Галка "Plain Char is Signed" сброшена. Всего лишь оптимизация умного компилятора Вы сами подумайте: раз Вы результат обратно сокращаете до 8 бит, то зачем тогда старшие биты вычислять? А если их вычислять не нужно, то можно ограничиться командами LDRB как более "дешёвыми". Тест Ваш построен некорректно. Для корректности теста сделайте int volatile c. Тогда, думаю, увидите LDRSB. Ну и для теста можно одно из a или b сделать отрицательным. Цитата(Arlleex @ Aug 25 2018, 12:23) 0x080002EA B240 SXTB r0,r0 ; ИМХО, лишнее, т.к. SUBS работает 32-битными числами Хоть это и лишнее, но это был намёк компилятора, что он заметил достаточность использования 8-бит для результата и поэтому не стал заморачиваться с правильным расширением входных аргументов. PS: Код теста не совсем корректный, так как должен вызвать warning "undefined behavior".
|
|
|
|
|
Aug 25 2018, 10:24
|
Местный
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264
|
Цитата(jcxz @ Aug 25 2018, 12:59) Тест Ваш построен некорректно. Для корректности теста сделайте int volatile c. Тогда, думаю, увидите LDRSB. Точно! И вправду LDRB заменились на LDRSB... Просто с расширением знака. Все четко по описанию команды загрузки с расширением знака Единственное, что отмечу. Разницы в количестве тактов выполнения не заметно... То есть по факту выполняются они одинаково по времени, только лишь представление числа в памяти нужным образом расширяется или нет, вот и вся разница, вроде как. Цитата(jcxz @ Aug 25 2018, 12:59) PS: Код теста не совсем корректный, так как должен вызвать warning "undefined behavior". Из-за int перед main() и отсутствия возвращаемого результата? Тогда не неопределенное поведение, а что-то типа "недостижимый участок кода" и "отсутствие возвращаемого значения в функции, которая возвращает int"... Но Keil не паникует, кстати...
|
|
|
|
|
Aug 25 2018, 12:24
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(Arlleex @ Aug 25 2018, 13:24) Единственное, что отмечу. Разницы в количестве тактов выполнения не заметно... То есть по факту выполняются они одинаково по времени, только лишь представление числа в памяти нужным образом расширяется или нет, вот и вся разница, вроде как. Конечно разницы в тактах нет при условии наличия команды в кеше/конвеере CPU. Но в реальном МК команду ещё нужно выбрать из памяти, а ширина шины к памяти программ не бесконечна, как и скорость последней. Так что по времени выполнения - Вы не правы. Цитата(Arlleex @ Aug 25 2018, 13:24) Из-за int перед main() и отсутствия возвращаемого результата? Нет. Из-за того, что в одном выражении используются две volatile-переменные. Порядок чтения которых внутри выражения неопределён. А volatile подразумевает строгость в порядке доступа. Цитата(Arlleex @ Aug 25 2018, 13:24) Но Keil не паникует, кстати... А зря. IAR реагирует на подобные выражения: "undefined behavior".
|
|
|
|
|
Aug 25 2018, 13:23
|
Местный
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264
|
Цитата(jcxz @ Aug 25 2018, 15:24) Конечно разницы в тактах нет при условии наличия команды в кеше/конвеере CPU. Но в реальном МК команду ещё нужно выбрать из памяти, а ширина шины к памяти программ не бесконечна, как и скорость последней. Так что по времени выполнения - Вы не правы. Открыл TRM на Cortex-M3. Вижу, что CPI на LDRB и на LDRSB одинаковы и составляют 2 такта. Одинакова и их синтаксическая запись. Существуют как 16-битные, так и 32-битные версии обеих команд. При всех прочих равных условиях время выполнения LDRB и LDRSB одинаково. То, что команду нужно выбрать из памяти - это понятно. Но LDRB нужно выбрать точно так же, как и LDRSB в одном и том же коде. Ничем не отличается. Другое дело, если мы говорим о том, что загружать значение как оно есть и лишь потом программно еще расширять знак. Там да, несколько команд нужно: тот же LDRB + расширение знака, если требуется. Цитата(jcxz @ Aug 25 2018, 15:24) Нет. Из-за того, что в одном выражении используются две volatile-переменные. Порядок чтения которых внутри выражения неопределён. А volatile подразумевает строгость в порядке доступа. Да, в упор не увидел очевидное... Жаль Keil не ругнулся никак даже при установке "All Warnings" в настройках компилятора
Сообщение отредактировал Arlleex - Aug 25 2018, 13:24
|
|
|
|
|
Aug 25 2018, 13:49
|
Гуру
Группа: Свой
Сообщений: 5 228
Регистрация: 3-07-08
Из: Омск
Пользователь №: 38 713
|
Цитата(Arlleex @ Aug 25 2018, 16:23) Открыл TRM на Cortex-M3. Вижу, что CPI на LDRB и на LDRSB одинаковы и составляют 2 такта. Одинакова и их синтаксическая запись. Существуют как 16-битные, так и 32-битные версии обеих команд. При всех прочих равных условиях время выполнения LDRB и LDRSB одинаково. А Вы когда-нибудь пробовали заглядывать в листинг? И сколько вы там видели LDRB разной длины и сколько LDRSB? Формы-то может и есть, тут вопрос в количестве.... Попробуйте в .asm-файле ввести 2 такие команды и скомпилить: Код LDRB R0, [R0, #0] LDRSB R0, [R0, #0] А потом попробуйте поизменять регистры от R0 до R7 и посмотреть что получается. А теперь загляните в листинги и увидите, что большинство обращений к памяти как раз подобные формы команд: косвенная с константным смещением.
|
|
|
|
|
Aug 25 2018, 14:15
|
Местный
Группа: Участник
Сообщений: 492
Регистрация: 12-11-11
Пользователь №: 68 264
|
Цитата(jcxz @ Aug 25 2018, 16:49) А Вы когда-нибудь пробовали заглядывать в листинг? И сколько вы там видели LDRB разной длины и сколько LDRSB? Формы-то может и есть, тут вопрос в количестве.... Мда, в листинге действительно LDRSB используются всегда 32-битные, очевиден проигрыш... Причем какие бы регистры не использовали - младшие или старшие - все равно берется команда Thumb-2 (32 бит). А вот LDRB, при использовании младших регистров в качестве операндов, компилируется в 16-битной Thumb форме; при использовании старших регистров - законно Thumb-2. P.S. Почитал тут в мануале. Если запись команды LDRSB использует форму с непосредственным смещением от базового регистра, то такая команда существует только 32-битная. Для LDRB такая команда есть в 16 битах, только там непосредственное значение ограничено 5 битами. Теперь все понятно! jcxz, благодарю за полезную информацию
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|