Несколько лет назад GCC давал отвратительный код; не думаю, чтобы что-то сильно изменилось. Кейловский (родной, не Кланг) куда лучше выдавал, но там другая проблема: АРМ забила на свой компилятор и переключилась на Кланг, который нередко выдаёт менее качественный код. Вообще, не помнить содержимое регистров и повторно производить загрузки или же заниматься бесполезными пересылками из регистра в регистр -- это нынче норма жизни для компиляторов.
А можно какой-нибудь пример подобного кода, который будет неэффективно скомпилен? Не ради докопаться или поспорить, но любопытно и правда посмотреть, попробовать разобраться. Может там ключиками решается или еще что. Да и просто знать подобные подводные камни.
А можно какой-нибудь пример подобного кода, который будет неэффективно скомпилен? Не ради докопаться или поспорить, но любопытно и правда посмотреть, попробовать разобраться. Может там ключиками решается или еще что. Да и просто знать подобные подводные камни.
Pval() - это у меня макрос чтения состояния одного бита порта GPIO (этот макрос для PIN_PRND_B должен развернуться в (*(u32 volatile *)IO_ADDR >> 0 & 1). Как видно - строчку "c -= Pval(PIN_PRND_B) * 2" я написал специально с таким расчётом, чтобы компилятор после LDR сделал всего две команды: выделение бита из считанного слова и вычитание его из c (думал помочь ему ). Но он зачем-то влепил 3 команды.
Дык volatile же. Поэтому всё строго. Сначала свдиг, потом И.
volatile действует только на операции доступа к памяти - не должен меняться их порядок. А к содержимому регистров отношения не имеет. Что и подтверждается компиляцией того же самого кода в режиме максимальной оптимизации, при которой компилятор создаёт те же самые команды, только вначале ставит обе LDR одна за другой, а потом после - все остальные арифметические команды:
т.е. - 2 команды, 2+4 байта. Но на такое я уже не надеялся практически. Так только человек сможет оптимизировать.
Что касается последнего варианта, то он не всегда оптимален: зависит от конкретного варианта конкретного ядра. Дело в том, что многоразрядный сдвиг за 1 такт требует соответствующего сдвигателя, а им могут пожертвовать для уменьшения размеров проца. И тогда LSLS будет сдвигать по одному биту за такт Зато если есть гарантия, что сдвиг будет за 1 такт, он действительно лучший (те же 2 такта, не считая собственно выборки из памяти, но 6 байтов, а не 8 ).
А вот хотел спросить, вообще есть какая нибудь книга, или руководство по программированию этих стм32 на Си, вроде Фрунзе и Магды для 8051, или Ревича и Белова для AVR? Я так понимаю, про комповый Си (как и про комповый ассемблер) читать бесполезно, там все по-другому.
Последний раз редактировалось Shuspano Сб ноя 23, 2019 15:20:37, всего редактировалось 1 раз.
А чем же "комповый" С отличается от "железячного"? Абсолютно одно и то же!
_________________ Linux rules! Windows must die. Здравомыслящий человек добровольно будет пользоваться мастдаем лишь в двух случаях: под дулом автомата или под влиянием анального зонда. Я на гитхабе, в ЖЖ
Что касается последнего варианта, то он не всегда оптимален: зависит от конкретного варианта конкретного ядра.
Мы обсуждаем работу компилятора при создании кода для конкретного ядра CM4F (указанного в свойствах проекта). Компилятор имхо должен проводить оптимизацию под конкретное ядро, а не под коня в вакууме. А в CM4F все использованные команды (кроме LDR) - однотактные.
Неправильно скомпилили. Во-первых: Если посмотреть на тот код, что я приводил, видно что PIN_PRND_B - выделяет 0-й бит из некоего IO-порта, а PIN_PRND_F - 10-й бит из другого IO-порта. у Вас в обоих случаях выделяется 0-й бит. Поэтому компилятор выполнил оптимизацию, видимо поместив #1 в R1. Во-вторых: Где-то до этого кода должна быть загрузка #1 в R1 (MOVS R1, #1) которую Вы не привели - а это ещё одна команда. В-третьих: Странно что компилятор у Вас выполнил загрузку #1 в R1, а потом сделал AND с R1. В сумме это требует 3 команды, в то время как с константой #1 в коде команды это можно было сделать за 2 команды. Или у Вас включена оптимизация по размеру, а не по скорости, или выбрано неправильное ядро (не CM3, CM4F). В-четвёртых: Компилятор у Вас зачем то перегружал повторно указатель, потратив на это лишние команды LDR. Возможно как-то неправильно объявлен указатель на IO-порт. Хотя это уже и не относится к вопросу....
>> Читать мануал на желаемый МК, мануал на ядро и посмотреть примеры программ для данного МК. Ну и подучить си конечно.
Я так понял, человек не про это спрашивает. Интересует что-то, где хорошо описывалось бы программирование для STM со всеми его библиотеками и периферией.
Фух... вроде мигает. Да, от знания асма толку никакого вообще. Ну да ладно. мне вот интересен еще момент. Почему если подпрограмму пишу где нить внизу листинга, а вызываю ее где нибудь вверху, например:
Код:
while (1) { ... delay(8000000); ... }
void delay(uint16_t time) {}
то транслятор ругается. Транслирует, но в итоге задержка не работает. А в асме это не разу не проблема.
Сейчас этот форум просматривают: нет зарегистрированных пользователей и гости: 16
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения