Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: новая проблема Оптимизация компилятора IAR
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
Alex ma
Есть глобальная структура с 4 переменными которые используются во функции MiDI
По адресу 01F4.

Есть функция:
void MiDI(void){
while(1){
здесь код.
ret //выход
};
};

Данная функция вызывается из другого места по указателю на нее.
Выполнив нужные действия выходим из нее, потом возвращаемся обратно, при минимальной оптимизации все нормально вот асм:
4: void MiDI (void){
+000005EF: C020 RJMP PC+0x0021 Relative jump

Но стоит повысить оптимизацию так вот получается вот что асм
4: void MiDI (void){
+00000444: 93BA ST -Y,R27 Store indirect and predecrement
+00000445: 93AA ST -Y,R26 Store indirect and predecrement
+00000446: EFA4 LDI R26,0xF4 Load immediate
+00000447: E0B1 LDI R27,0x01 Load immediate
+00000448: C020 RJMP PC+0x0021 Relative jump

СОХРАНЯЕТ В СТЕКЕ ДАННЫХ регистры R27, R26!
Он думает цикл бесконечный а, я выхожу из него ! по ret (макрос), и происходит потеря данных, ведь я не восстанавливаю из стека данных.
Как компилятор отучить делать вот так
+00000444: 93BA ST -Y,R27 Store indirect and predecrement
+00000445: 93AA ST -Y,R26 Store indirect and predecrement
rezident
Попробуйте выходить по break, а ret поставить после бесконечного цикла.
Цикл с выходом из середины (Википедия). Или см. K&R раздел 3.7. Оператор BREAK.
Alex ma
Цитата(rezident @ Mar 21 2007, 22:21) *
Попробуйте выходить по break, а ret поставить после бесконечного цикла.
Цикл с выходом из середины (Википедия). Или см. K&R раздел 3.7. Оператор BREAK.


Решил проблему в лоб, спрятал работу со структурой в функцию processingDI();
Теперь функция с бесконечным циклом MiDI состоит только из переключателя switch и функций. Данных нет. :
void MiDI(void){ //
while(1){
processingDI();
switch(GetExeKey()){ //здесь считываем функцией переменную из структуры, которую //обрабатывает processingDI();
case DI_UP_FAN:{
OutFan(0);
Delay(2, MiDIPr);
UpDownFan(UP);
}
И т.д.

Асм при старте void MiDI(void)
4: void MiDI(void){
+0000045D: C020 RJMP PC+0x0021 Relative jump – переход на processingDI();
Теперь при максимальной оптимизации по скорости все нормально работает



Вот асм функции processingDI();
180: void processingDI(void){
+000001BB: 93BA ST -Y,R27 Store indirect and predecrement
+000001BC: 93AA ST -Y,R26 Store indirect and predecrement
181: key.currentKey = ReadDI();
Здесь еще код для работы сос структурой
: key.previousKey = key.currentKey;
+000001CD: 930C ST X,R16 Store indirect
190: };
+000001CE: 91A9 LD R26,Y+ Load indirect and postincrement
+000001CF: 91B9 LD R27,Y+ Load indirect and postincrement
+000001D0: 9508 RET Subroutine return
IgorKossak
Каков смысл городить ret (макрос), если стандартного return(); вполне достаточно для корректного выхода из любого цикла, да и из функции заодно?
Alex ma
Цитата(IgorKossak @ Mar 22 2007, 14:45) *
Каков смысл городить ret (макрос), если стандартного return(); вполне достаточно для корректного выхода из любого цикла, да и из функции заодно?


Error[Pe118]: a void function may not return a value E:\Documens\Alex\Ìîè äîêóìåíòû\MUKS-01\MUKS01v02\task.c 10
это на return();
rezident
Цитата(Alex ma @ Mar 22 2007, 21:04) *
Error[Pe118]: a void function may not return a value E:\Documens\Alex\Ìîè äîêóìåíòû\MUKS-01\MUKS01v02\task.c 10
это на return();

Все верно ошибку компилятор выдает. "Пустая" функция не может возвращать значение.
И все же стандартизованный способ прерывания цикла это оператор break. wink.gif В крайнем случае goto на метку вне цикла.
singlskv
Цитата(Alex ma @ Mar 22 2007, 19:04) *
Error[Pe118]: a void function may not return a value E:\Documens\Alex\Ìîè äîêóìåíòû\MUKS-01\MUKS01v02\task.c 10
это на return();

А что оно говорит если написать так return; // без скобочек ?

Цитата(rezident @ Mar 22 2007, 19:28) *
Все верно ошибку компилятор выдает. "Пустая" функция не может возвращать значение.
И все же стандартизованный способ прерывания цикла это оператор break. wink.gif В крайнем случае goto на метку вне цикла.

return это вполне валидный способ прекращения цикла,
а вот goto - не всегда
при использовании goto можно легко получать переполнение стека,
если его использовать необдуманно
zltigo
Цитата(singlskv @ Mar 22 2007, 23:17) *
при использовании goto можно легко получать переполнение стека,
если его использовать необдуманно

Легко? Cтрашилка. Никакое необдуманоое и даже преднамеренное "плохое" использование goto не должно приводить к переполнению стека или каким либо другим деструктивным последствиям при сколь-нибудь пригодном для работы компиляторе языка высокого уровня. Потеря оптимальности кода может в некоторых "необдуманных" случаях действительно заметной.
singlskv
Цитата(zltigo @ Mar 23 2007, 00:50) *
Легко? Cтрашилка. Никакое необдуманоое и даже преднамеренное "плохое" использование goto не должно приводить к переполнению стека или каким либо другим деструктивным последствиям при сколь-нибудь пригодном для работы компиляторе языка высокого уровня. Потеря оптимальности кода может в некоторых "необдуманных" случаях действительно заметной.

goto не возвращает стек в исходное состояние, то есть если переменная была заведена
на стеке то стек будет расходоваться зазря до выхода из функции
ну и в принципе можно нарисовать такую ситуацию когда отведенного стека
просто не хватит
наверное на AVR это не очень актуальная проблемма, но например на
PC легко таким образом организовать переполнение
zltigo
Цитата(singlskv @ Mar 23 2007, 00:26) *
goto не возвращает стек в исходное состояние, то есть если переменная была заведена
на стеке то стек будет расходоваться зазря до выхода из функции

А return, типа, возвращает, поскольку из функции выходит smile.gif.
Весь обьем стека под локальные переменные выделяется сразу и соответственно освобождается сразу а не по кусочкам. Другого поведения для компиляторов с языков высокого уровня не наблюдал ни разу. В поминаемом далее PC, вообще комады enter, leave для организации единого стекового фрейма заведены..
Цитата
ну и в принципе можно нарисовать такую ситуацию когда отведенного стека
просто не хватит

Легко, только goto к этому ни сном ни духом.
Цитата
наверное на AVR это не очень актуальная проблемма,

Мало памяти - мало проблем smile.gif
Цитата
но например на PC легко таким образом организовать переполнение

Каким таким "таким образом"???
Rst7
Цитата(singlskv @ Mar 23 2007, 00:26) *
goto не возвращает стек в исходное состояние, то есть если переменная была заведена
на стеке то стек будет расходоваться зазря до выхода из функции


Дело в том, что это вас интересовать не должно. Компилятор (ИАР особенно) - он грамотный, он посмотрит, как все выполняется, и переменную уберет (или не уберет) из стека в нужный момент. Обычно этот момент - всегда выход из функции, т.к. постоянно дергать стек вперед/назад довольно накладно. Так что пользуйте goto, пользуйте return, break, все будет ок, а вот ассемблеровкий ret поперк - это неправильно в любом случае.

И вообще, правильно написаная программа должна компилироваться с макс. оптимизацией и работать. Если такого не происходит, ищите ошибки у себя (обычное дело - volatile забыли, вот как у вас - ret поперек всадили - это даже не ошибка, это... Ну не хочу плохие слова говорить wink.gif )
_Bill
Цитата(Alex ma @ Mar 21 2007, 20:03) *
Есть глобальная структура с 4 переменными которые используются во функции MiDI
По адресу 01F4.

Есть функция:
void MiDI(void){
while(1){
здесь код.
ret //выход
};
};

Приведите весь код полностью, тогда все ясно будет.
singlskv
Цитата(zltigo @ Mar 23 2007, 09:07) *
А return, типа, возвращает, поскольку из функции выходит smile.gif.

конечно, return; всегда востанавливает указатель стека smile.gif
Цитата
Весь обьем стека под локальные переменные выделяется сразу и соответственно освобождается сразу а не по кусочкам. Другого поведения для компиляторов с языков высокого уровня не наблюдал ни разу.

Хорошо, сколько по вашему должен расходовать стека данных
следующий код на хорошем компиляторе ?
Код

void func()
{
  while(.......)
  {
     char str1[10];
     .................
     .................
  }

  while ( ........)
  {
    char str2[12];
    ..................
    ..................
  }
}

12 или 22 байта ?
а если будут множественное goto причем как вперед так и назад ?

Цитата
Мало памяти - мало проблем smile.gif

много регистров меньше проблем smile.gif
Rst7
Цитата
12 или 22 байта ?а если будут множественное goto причем как вперед так и назад ?

Если без goto - иар постелит 12 байт, если будут goto - 22. Не волнуйтесь за компилятор.
xemul
Цитата(singlskv @ Mar 24 2007, 01:06) *
Хорошо, сколько по вашему должен расходовать стека данных
следующий код на хорошем компиляторе ?
12 или 22 байта?
а если будут множественное goto причем как вперед так и назад ?

Собственно Rst7 уже ответил. Позволю добавить, что даже при определении переменной внутри оператора место на стеке под нее будет выделено при входе в функцию (оптимизатор может, конечно, затолкнуть переменную и в регистры, но мы сейчас не о том).
Без оптимизации на стеке будет по-любому выделено 22 байта, а уж что оптимизатор сможет наоптимизировать... Это к оптимизаторуsmile.gif
zltigo
Цитата(singlskv @ Mar 24 2007, 00:06) *
а если будут множественное goto причем как вперед так и назад ?

1.Добавление к указанному гладкому (с точки зрения использования двух локальных массвов )алгоритму множества goto вперед/назад сдеает его просто другим и бессмысленным для сравнения с приведенным.
2.Если желаете гарантированно в любой ситуации не зависимо ни от чего иметь перекрывающиеся области памяти для массивов не используйте для них разные имена smile.gif или используйте union smile.gif
singlskv
Цитата(zltigo @ Mar 24 2007, 12:32) *
1.Добавление к указанному гладкому (с точки зрения использования двух локальных массвов )алгоритму множества goto вперед/назад сдеает его просто другим и бессмысленным для сравнения с приведенным.
2.Если желаете гарантированно в любой ситуации не зависимо ни от чего иметь перекрывающиеся области памяти для массивов не используйте для них разные имена smile.gif или используйте union smile.gif


1.Ну так собственно об этом и шла речь.
Необдуманное goto при том же (с точки зрения результата) алгоритме может
приводить к неоправданному перерасходу стека.
2. Понятно что я так вобще никогда не напишу smile.gif
Это был всего лишь пример.
zltigo
Цитата(singlskv @ Mar 24 2007, 11:38) *
...
Необдуманное goto при том же (с точки зрения результата) алгоритме может
приводить к неоправданному перерасходу стека.
...
Это был всего лишь пример.

И где примеры ДВУХ разных реализаций ОДНОГО алгоритма один из которых приводит к перерасходу стека? Пока что привели некий кусочек, и на словах сообщили, что если теперь туда напихать всяких разных goto (и тем самым на мой взгляд сделать результат его выполнения другим) то компилятору пополхеет. Я конечно могу себе представить попытку некого экзерсиса утыканного goto вместо любых других конструкций, но назвать его "необдуманым использованием goto" я уж точно не смогу smile.gif -
это будет тщательное с "заранее обдумаными намерениями" smile.gif запихивание goto во все места smile.gif. Кроме того, если Вы представите такой экзерсис, то я пожалуй смогу с добиться одинакового использования стека (под явно обьявленные в функции локальные переменные) функцией не покусившись ни на один из любовно расставленных goto.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.