Variable optimized out

Кто любит RISC в жизни, заходим, не стесняемся.
Ответить
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Ср фев 13, 2019 15:07:44

Сообщение Accel »

Доброго времени суток.

Перехожу с аврок на стм32, приходится писать на С. Столкнулся с проблемой: при включении оптимизации компилятора нижеприведенный код (приведен в упрощенном виде) выщёлкивается из итогового образа напрочь.

Код: Выделить всё

void InitRCC_HSE() {
	uint32_t cycle_counter;

	cycle_counter = 0;

	//Ждем заданное количество циклов флага стабильности частоты HSE
	while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) {
		cycle_counter++;

		if (cycle_counter == HSE_READY_TIMEOUT) {
			//дальше обработка ошибки
		}
	}
[/color]
Если cycle_counter объявить как volatile - всё работает, но если нет, то цикл при включенной оптмизиации в итоговый код не попадает.
Как же так, условие в while(...) же не статическое, RCC->CR в коде CMSIS объявлено как __IO uint32_t CR; где __IO - алиас для того же volatile, соответственно, его значение на этапе компиляции не определено. Чтобы выкинуть кусок кода, компилятор должен быть уверен, что код никогда не будет выполнен. Здесь же он вполне себе выполняется из-за того, что значение регистра меняется извне, и об этом компилятору дана соответствующая директива (__IO uint32_t CR;).

Вопрос - в чем логика такого поведения компилятора (gcc@STM32CubeIDE).
Реклама
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

Такой код компилятор выкидывать не должен, мой gcc 10 ничем подобным и не занимается.
Реклама
Мудрый кот
Сообщения: 1759
Зарегистрирован: Пт июн 01, 2018 07:28:45

Сообщение parovoZZ »

должен быть квалификатор volatile
Модератор
Аватара пользователя
Сообщения: 4614
Зарегистрирован: Чт мар 18, 2010 23:09:57
Откуда: Планета Земля

Сообщение Аlex »

[uquote="parovoZZ",url="/forum/viewtopic.php?p=4052491#p4052491"]должен быть квалификатор volatile[/uquote]
Аргументируйте. Тоже не вижу ничего плохого в этом коде.
Реклама
Эиком - электронные компоненты и радиодетали
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Ср фев 13, 2019 15:07:44

Сообщение Accel »

Спасибо всем, кто откликнулся, стал копать на тему того, конкретно какие инструкции вылетают и нашел свою ошибку. Оказалось, что:

а). Да, действительно локальную переменную компилятор оптимизирует без последствий, но не прям выкинув, а используя на участке кода под ее значение один из регистров общего назначения (не выделяя под нее sram), загрузив на старте в него непосредственное значение (HSE_READY_TIMEOUT, в моем случае равном 250), и декрементируя на каждой итерации цикла и сравнивая с нулём для выполнения условного перехода (поэтому в дебаггере я не мог посмотреть на значение переменной, которой нет, поэтому "variable optimized out").

б). Я выбрал слишком маленькое значение этой константы: на другом кварце частота HSE фиксировалась ещё до 80й итерации цикла, поэтому в константе задал с некоторым запасом (250). Оказалось, что новый кварц стабилизируется дольше. На неоптимизированной версии стабилизация происходила чуть раньше 250й итерации цикла, а на оптимизированной - чуть после (повезло :facepalm:), т.к. неоптмизированный код цикла содержал 3 лишних ассемблерных инструкции, соответственно, в абсолютном выражении работал чуть дольше. Поэтому одна версия впритирку пролазила в таймаут стабилизации HSE, а другая - валилась в ошибку. Увеличил таймаут до 2000 - всё стало ок :beer:.
Реклама
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

Не надо впритирку. Это же защитный механизм. Завтра другая температура, контролер, кварц или ёмкости и опять "не успет". Я бы ещё на пару порядков счётчик увеличил. Какая разница, через 1, 10 или 100 мс вы узнаете о неисправности кварца.
Реклама
Мудрый кот
Сообщения: 1780
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="Accel",url="/forum/viewtopic.php?p=4052505#p4052505"]Увеличил таймаут до 2000 - всё стало ок :beer:.[/uquote]250 - пальцем в небо, 2000 - опять наугад. Да ещё и - зависимо от того, насколько оптимальным будет код... :facepalm:
А ведь в даташитах/юзер-мануалах обычно приводят времена стабилизации генераторов.

Добавлено after 6 minutes 12 seconds:
[uquote="VladislavS",url="/forum/viewtopic.php?p=4052523#p4052523"]Я бы ещё на пару порядков счётчик увеличил. Какая разница, через 1, 10 или 100 мс вы узнаете о неисправности кварца.[/uquote]Для некоторых классов устройств регламентируется максимально допустимое время выхода устройства в рабочий режим после подачи питания. Или же - максимально допустимое время начала выполнения какой-то определённой критичной функции (даже если в целом весь функционал устройства ещё не запустился к этому моменту). И 100мс может оказаться слишком много. Да даже и 10.
Первый раз сказал Мяу!
Сообщения: 27
Зарегистрирован: Ср фев 13, 2019 15:07:44

Сообщение Accel »

[uquote="jcxz",url="/forum/viewtopic.php?p=4052630#p4052630"][uquote="Accel",url="/forum/viewtopic.php?p=4052505#p4052505"]Увеличил таймаут до 2000 - всё стало ок :beer:.[/uquote]250 - пальцем в небо, 2000 - опять наугад. Да ещё и - зависимо от того, насколько оптимальным будет код... :facepalm:[/uquote]
Согласен, но в даташите тоже указано "Startup time - 2ms" с припиской, что может меняться в больших пределах, в зависимости от качества кварца. Видимо, по фен-шую всё-таки заюзаю SysTick, чтобы отмерять интервалы им, и добавлю конский запас. Спасибо.
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="jcxz",url="/forum/viewtopic.php?p=4052630#p4052630"]И 100мс может оказаться слишком много. Да даже и 10.[/uquote]Кто мешает сделать критическпе вещи, если они действительно есть, до старта кварца? Заодно и время ожидания зря не пройдёт.
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17

Сообщение AVI-crak »

[uquote="Accel",url="/forum/viewtopic.php?p=4052481#p4052481"]при включении оптимизации компилятора нижеприведенный код (приведен в упрощенном виде) выщёлкивается из итогового образа напрочь[/uquote]
Макрос в цикле разворачивается до:

Код: Выделить всё

#define READ_BIT(REG, BIT)    ((REG) & (BIT))
При этом первый параметр имеет атрибут volatile на чтение и запись, однако к нему применяется дополнительный оператор "И" в теле макроса, отчего атрибут теряется.
Для того чтобы обойти это ограничение, достаточно не использовать макрос. Так и запись получается короче, и проще.

Код: Выделить всё

cycle_counter = HSE_READY_TIMEOUT;
while ((!(RCC->CR & RCC_CR_HSERDY)) && --cycle_counter);
if(cycle_counter == 0) {флаг не взвёлся}
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4052976#p4052976"]Макрос в цикле разворачивается до:

Код: Выделить всё

#define READ_BIT(REG, BIT)    ((REG) & (BIT))
При этом первый параметр имеет атрибут volatile на чтение и запись, однако к нему применяется дополнительный оператор "И" в теле макроса, отчего атрибут теряется.[/uquote]
Оператор "И" применяется к прочитанному из регистра значению, никакие атрибуты там не теряются.
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17

Сообщение AVI-crak »

[uquote="Reflector",url="/forum/viewtopic.php?p=4052986#p4052986"]никакие атрибуты там не теряются.[/uquote]
Наследие атрибута сохраняется до первого применения внешнего оператора. Название макроса является именем новой переменной уже без атрибутов (да, они именно так и работают). Кроме того, по документации не взведённый RCC_CR_HSERDY равен нулю - первоначальный код вообще не рабочий, в том числе и ограничитель времени (там вообще ересь).
Контактная информация:
Мудрый кот
Сообщения: 1780
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="VladislavS",url="/forum/viewtopic.php?p=4052842#p4052842"]Кто мешает сделать критическпе вещи, если они действительно есть, до старта кварца? Заодно и время ожидания зря не пройдёт.[/uquote]"Критически важные вещи" могут включать запуск каких-то служб, для запуска которых нужно например чтение из внешнего чипа SPI-флешь (конфиг и т.д.). Хранение этого конфига во флешь может осуществляться в сложных структурах: кольцевые буфера, ФС, ...
Предлагаете писать два набора API для работы с флешь и структурами хранения данных в ней: для работы до старта кварца и для работы с кварцем?? :facepalm:
К тому же - и все эти службы, время запуска которых критично, они тоже должны как-то плавно пережить переключение источника тактирования....
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4053049#p4053049"]Наследие атрибута сохраняется до первого применения внешнего оператора. Название макроса является именем новой переменной уже без атрибутов (да, они именно так и работают).[/uquote]
Первый раз подобное слышу :) Если изначально было:

Код: Выделить всё

while (READ_BIT(RCC->CR, RCC_CR_HSERDY) == 0U) 
то после обработки препроцессором получим:

Код: Выделить всё

while (((RCC->CR) & (RCC_CR_HSERDY)) == 0U)
И я это не выдумал, а скопировал из вывода gcc после скармливания ему ключа "-E". Где тут новая переменная?
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17

Сообщение AVI-crak »

[uquote="Reflector",url="/forum/viewtopic.php?p=4053098#p4053098"]Первый раз подобное слышу :)[/uquote]
Лучше поздно, чем никогда. :)
Я повторюсь, значение атрибута сохраняется до первого оператора присвоения. И оно там не в воздухе висит, для него даже имя есть, точно такое-же как у названия макроса. Это естественное ограничение GCC, от присвоения volatile всем переменным проекта.
В операцию сравнения идёт имя макроса, а не его содержимое.
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4053122#p4053122"]Я повторюсь, значение атрибута сохраняется до первого оператора присвоения. И оно там не в воздухе висит, для него даже имя есть, точно такое-же как у названия макроса. Это естественное ограничение GCC, от присвоения volatile всем переменным проекта.[/uquote]
При разворачивании макроса происходит простая подстановка, в этот момент компилятор еще не знает что такое RCC->CR, определено ли оно где-то и какие там у него атрибуты, а после подстановки, т.е. когда наличие volatile может иметь значение, уже нет никаких макросов...
Собутыльник Кота
Аватара пользователя
Сообщения: 2567
Зарегистрирован: Вт май 01, 2018 19:44:47

Сообщение VladislavS »

[uquote="jcxz",url="/forum/viewtopic.php?p=4053052#p4053052"]К тому же - и все эти службы, время запуска которых критично, они тоже должны как-то плавно пережить переключение источника тактирования....[/uquote]Сова на глобусе. Если кварц запускается, в штатном режиме, никаких лишних задержек не будет. А в аварийном режиме действительно КРИТИЧЕСКАЯ служба должна уметь без кварца работать. Иначе никакая она не критическая.

Добавлено after 16 minutes 16 seconds:
[uquote="AVI-crak",url="/forum/viewtopic.php?p=4053122#p4053122"]В операцию сравнения идёт имя макроса, а не его содержимое.[/uquote]Надеюсь, это просто жара...
Прорезались зубы
Аватара пользователя
Сообщения: 202
Зарегистрирован: Сб янв 09, 2016 15:51:17

Сообщение AVI-crak »

VladislavS, Reflector - Всегда можно проверить на практике.
Контактная информация:
Поставщик валерьянки для Кота
Сообщения: 2089
Зарегистрирован: Вс июн 19, 2016 09:32:03
Re:

Сообщение Reflector »

[uquote="AVI-crak",url="/forum/viewtopic.php?p=4053380#p4053380"]Всегда можно проверить на практике.[/uquote]
Я же вчера продемонстрировал как будет выглядеть код после стадии препроцессинга... Можно чуть поменять макрос и тогда получим точно такую строку как ты сам и предлагал. Так, например. Справа промежуточное представление кода, мы просто тормознули компилятор на этой стадии, никто ведь не станет доказывать что одинаковые строки скомпилируются по-разному просто потому, что раньше в одной из них был макрос :) И все компиляторы которые там можно выбрать естественно выдают одно и то же.
Мудрый кот
Сообщения: 1780
Зарегистрирован: Вт авг 15, 2017 10:51:13

Сообщение jcxz »

[uquote="VladislavS",url="/forum/viewtopic.php?p=4053362#p4053362"]Если кварц запускается, в штатном режиме, никаких лишних задержек не будет. А в аварийном режиме действительно КРИТИЧЕСКАЯ служба должна уметь без кварца работать. Иначе никакая она не критическая.[/uquote]Разговор не про "критические службы", а про службы время старта которых, после включения_питания/сброса критично, не должно превышать максимально допустимое. И тупо ждать 100мс чего-то (когда это не нужно), до того как запустить такую службу - слишком расточительно.
Ответить

Вернуться в «ARM»