Несколько лет назад 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) {}
то транслятор ругается. Транслирует, но в итоге задержка не работает. А в асме это не разу не проблема.
Вы не можете начинать темы Вы не можете отвечать на сообщения Вы не можете редактировать свои сообщения Вы не можете удалять свои сообщения Вы не можете добавлять вложения