Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: IAR: Warning[Pa082]:
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > AVR
prottoss
Доброго времени суток!

Столкнулся с таким сообщением IAR Atmel AVR C/C++ Compiler V4.10B/W32, Evaluation Version

Имеется код:

Код
char volatile Line_Lenght1, Line_Lenght2;
char volatile Area_Height, Area_Width;

...

где-то в коде:

void Fun(void){

...

Area_Width = Line_Lenght1 + Line_Lenght2;

...

}


Для строчки "Area_Width = Line_Lenght1 + Line_Lenght2;" выводится предупреждение типа:

Warning[Pa082]: undefined behavior: the order of volatile accesses is undefined in this statement

И так почти во всех местах, где производятся операции с несколькими "volatile". Проект отлично работает, но данные предупреждения немного раздражают. Привык, что проект компилируется "чисто", без Warning-ов.

Может кто знает, как победить их?
vet
Вот так:
Код
Area_Width = Line_Lenght1;
Area_Width += Line_Lenght2;

и т. п.
PS: а так ли нужно объявлять volatile-ами с виду самые обычные переменные?
prottoss
Цитата(vet @ Feb 27 2006, 02:41) *
Вот так:
Код
Area_Width = Line_Lenght1;
Area_Width += Line_Lenght2;

и т. п.
PS: а так ли нужно объявлять volatile-ами с виду самые обычные переменные?


Это глобальные переменные, и при максимальной оптимизации, нектороые "оптимизируются", выкидываются вместе скодом, проще говоря :-)

Строка

Код
Area_Width += Line_Lenght2;


имеет то же самое предупреждение.

А как быть с кодом

Код
if(Line_Lenght1==Line_Lenght2){

}


с точно таким же предупреждением?
vet
Они так и будут появляться, всё ж заvolatilено smile.gif
Компилятор выкидывает при оптимизации то, что не влияет на результат вычислений, глобальность тут ни при чём. volatile имеет смысл применять в особых ситуациях - сделать задержку, вывести данные в порт и т. п.
Здесь же компилятор справедливо указывает, что одно из нескольких volatile будет прочитано/записано раньше. Можно отменить это предупреждение совсем. Но лучше убрать volatile-ы и дать компилятору развернуться с оптимизацией smile.gif
prottoss
Цитата(vet @ Feb 27 2006, 02:57) *
Они так и будут появляться, всё ж заvolatilено smile.gif
Компилятор выкидывает при оптимизации то, что не влияет на результат вычислений, глобальность тут ни при чём. volatile имеет смысл применять в особых ситуациях - сделать задержку, вывести данные в порт и т. п.
Здесь же компилятор справедливо указывает, что одно из нескольких volatile будет прочитано/записано раньше. Можно отменить это предупреждение совсем. Но лучше убрать volatile-ы и дать компилятору развернуться с оптимизацией smile.gif


Угу...сделал в точности так, код работает максимум на медиум, но ни как ни на максимальной (по размеру кода) оптимизации, и, естественно, раздулся...
vet
Я бы поискал по листингам, что именно перестало компилироваться, как нужно, и отчего; компилятору всё же склонен доверять.
Отключить предупреждение можно строкой #pragma diag_suppress=Pa082
defunct
Цитата(prottoss @ Feb 26 2006, 21:29) *


Компилятор хочет атомарности операций.. обеспечте ему их..

char temp;

temp = Line_Lenght2;
Area_Width = Line_Lenght1;
Area_Width += temp;


а какой смысл делать все переменные volatile? Делайте volatile только те, которые изменяются в разных трэдах.


Цитата
Угу...сделал в точности так, код работает максимум на медиум, но ни как ни на максимальной (по размеру кода) оптимизации, и, естественно, раздулся...

Вам памяти в чипе не хватает? Ну раздулся код и Бог с ним, зато возможно работать будет быстрее.
prottoss
Решил проблему...

В модуле 12 глобальных переменных и порядка 20-и функций обращающихся произволно к нескольким переменным. Если не ставил к типу переменной volatile, некторые переменные "оптимизировались". Объединил все переменные в одну структуру. Все всало на свои места. Компилятор перестал предупреждать, да и код стал поменьше немножко, что льстит моему эго :-). Просмотрел листинг - компилер, вместо загрузки в указатель адреса переменной стал в начале функции формировать указатель на структуру, а к элементам обращается по индексу. Красиво, блин.

Всем спасибо за советы.



Цитата(defunct @ Feb 27 2006, 03:34) *
Цитата(prottoss @ Feb 26 2006, 21:29) *


Компилятор хочет атомарности операций.. обеспечте ему их..

char temp;

temp = Line_Lenght2;
Area_Width = Line_Lenght1;
Area_Width += temp;


Это не помогает


Цитата(defunct @ Feb 27 2006, 03:34) *
а какой смысл делать все переменные volatile? Делайте volatile только те, которые изменяются в разных трэдах.


Согласен, смысла нет. Но на момент отладки так надежнее, я считаю.

Цитата(defunct @ Feb 27 2006, 03:34) *
Цитата
Угу...сделал в точности так, код работает максимум на медиум, но ни как ни на максимальной (по размеру кода) оптимизации, и, естественно, раздулся...

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


Я не люблю "возможно". Я пытаюсь всегда знать, что и как делает компилятор. Возможно ( :-) ), по этому в моем коде редкИ глюки :-)
abbot
Эх, когда же начнут читать документацию?
Volatile означает, что компилятору и оптимизатору запрещается делать какие-либо предположения относительно значения данной переменной, и обязательно необходимо читать эту переменную перед тем, как делать с ней что-либо (конечно, если эта переменная находится не в регистре, а в памяти). Больше ничего volatile не означает.

Откуда берется предупреждение: в вашем коде присутствует конструкция
Area_Width = Line_Lenght1 + Line_Lenght2;
в которой все переменные - volatile.
Если с присваиванием никаких вопросов у компилятора не возникает, то относительно конструкции Line_Length1 + Line_Length2 компилятор не знает, в каком порядке нужно прочитать значения переменных перед выполнением сложения - сначла первую, потом вторую, или наоборот. Очевидно, что результат может зависить от порядка, если значения переменных меняются, например, в ISR. И именно об этом компилятор вам и выводит предупреждение: он не может дать гарантии, в каком порядке произойдет чтение этих переменных перед сложением.

А теперь внимание, советы, которые здесь давали.
Ни в коем случае не стоит делать такой код!
Цитата
Area_Width = Line_Length1;
Area_Width += Line_Length2;

Он скомпилируется примерно в такое:
Загрузить Line_Length1 в регистр
Загрузить регистр в Area_Width
Загрузить Area_Width в регистр (это компилятор делает, так как Area_Width - тоже volatile и он мог измениться между этими двумя инструкциями)
Загрузить Line_Length2 в регистр
Сложить
Загрузить регистр в Area_Width

Как сделать правильно:
Цитата
register char tmp
tmp = Line_Length1;
Area_Width = tmp + Line_Length2;

Это скомпилируется в:
загрузить Line_Length1 в регистр
загрузить Line_Length2 в регистр
Сложить
Загрузить регистр в Area_Width

А вообще, почитайте документацию от IAR'а, которая идет в PDF'ах. Там много интересного пишут.
prottoss
2abbot :

Спасибо за исчерпывающий ответ. А дока читается по мере возникновения вопросов :-).
Alechin
Насчет выкидывания volatile: при этом действительно можно получить неработоспособный код - IAR "слишком умный" - если в какой-либо процедуре идет чтение глобальной переменной, и перед этим в процедуре нет записи в нее - компилятор использование этой переменной молча (заметьтьте - молча) выбрасывает из кода. Я для MSP430 очень долго не мог понять - почему основной цикл программы с условием завершения по такой, не описанной как volatile, переменной полностью был исключен из кода! Компилятор посчитал, что раз переменная в цикле нигде не модифицируется, то цикл никогда не будет выполнен.
dxp
Цитата(Alechin @ Feb 27 2006, 19:34) *
Насчет выкидывания volatile: при этом действительно можно получить неработоспособный код - IAR "слишком умный" - если в какой-либо процедуре идет чтение глобальной переменной, и перед этим в процедуре нет записи в нее - компилятор использование этой переменной молча (заметьтьте - молча) выбрасывает из кода. Я для MSP430 очень долго не мог понять - почему основной цикл программы с условием завершения по такой, не описанной как volatile, переменной полностью был исключен из кода! Компилятор посчитал, что раз переменная в цикле нигде не модифицируется, то цикл никогда не будет выполнен.

И совершенно правильно он делает. И то, что докапывается до этого - честь ему и хвала, потому как действительно дотошный и придирчивый компилятор, генерирующий хороший код, глядя на который, писать что-то на асме пропадает в подавляющем большинстве случаев само собой.

Что касается volatile. Volatile, как сказали, указание компилятору не оптимизировать объект. На самом деле это не совсем правильно, не совсем точно. Volatile - более близкий по смыслу перевод, - означает, что объект "подвижный", асинхронно изменяемый, т.е. объект может быть срытно изменен вне данного потока управления программы. И, следовательно, запрещает не все оптимизации, а только те, которые могут нарушить правильность работы по причине асинхронной изменяемости. Другие оптимизации вполне имеют право быть. Например, есть в EWAVR оптимизация clustering variables. Она сводится к тому, что компилятор логически объединяет рядом объявленные глобальные/статические объекты в "вируальную структуру" и обращается к этим объектам, не загружая каждый раз полный адрес для каждого объекта, а загрузив одни раз базовый адрес этой "виртуальной структуры", обращается к объектам со смещением, что есть наиболее эффективный способ адресации в AVR. И если пропускать обращение к объекту, объявленному как volatile, компилятор не имеет права, то делать кластеризацию с этим объектом - пожалуйста.

Т.ч. тут все не в компилятор упирается, а в программиста. Ошибка эта очень распространенная, все на эти грабли наступают и не один раз. И даже опытные товарищи забывают (вернее, упускают из виду) и тоже мимо граблей не проходят. Но откаываться от хорошей оптимизации, имхо, все-таки неправильно.
vet
Alechin
Можно глянуть на пример? для общего развития, чтоб лишний раз на грабли не наступать.
Alechin
Цитата(vet @ Feb 27 2006, 17:33) *
Alechin
Можно глянуть на пример? для общего развития, чтоб лишний раз на грабли не наступать.

К сожалению давно это было - сейчас ничего не осталось.
В приниципе можно написать самому тестовый пример (будет хорошей практикой). Главное сделать 2 модуля (файла). Обращаться из одного файла к переменной в другом файле (сделав ее "видимой").
Вернее даже не обращаться, а сделать по ней цикл, или ветвление, и посмотрить сгенерированный листинг.

А насчет ИАРа - все-таки варнинг надо было сделать на "с оптимизированный" код. Что бы не пришлось голову ломать. Ведь если бы я тогда не посмотрел исходник - никогда бы не понял, что произошло.
vet
Alechin
Мне, собственно, потому хотелось бы глянуть пример, что сам я с такими пропаданиями кода не сталкивался; правда, на IAR пишу только для ARM.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.