|
новая проблема Оптимизация компилятора IAR |
|
|
|
Mar 21 2007, 20:03
|
Частый гость
 
Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445

|
Есть глобальная структура с 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
|
|
|
|
|
Mar 21 2007, 21:14
|
Частый гость
 
Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445

|
Цитата(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
|
|
|
|
|
Mar 22 2007, 19:04
|
Частый гость
 
Группа: Новичок
Сообщений: 81
Регистрация: 9-08-06
Пользователь №: 19 445

|
Цитата(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();
|
|
|
|
|
Mar 22 2007, 19:28
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
Цитата(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.  В крайнем случае goto на метку вне цикла.
|
|
|
|
|
Mar 23 2007, 00:17
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(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.  В крайнем случае goto на метку вне цикла. return это вполне валидный способ прекращения цикла, а вот goto - не всегда при использовании goto можно легко получать переполнение стека, если его использовать необдуманно
|
|
|
|
|
Mar 23 2007, 01:26
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

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

Гуру
     
Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244

|
Цитата(singlskv @ Mar 23 2007, 00:26)  goto не возвращает стек в исходное состояние, то есть если переменная была заведена на стеке то стек будет расходоваться зазря до выхода из функции А return, типа, возвращает, поскольку из функции выходит  . Весь обьем стека под локальные переменные выделяется сразу и соответственно освобождается сразу а не по кусочкам. Другого поведения для компиляторов с языков высокого уровня не наблюдал ни разу. В поминаемом далее PC, вообще комады enter, leave для организации единого стекового фрейма заведены.. Цитата ну и в принципе можно нарисовать такую ситуацию когда отведенного стека просто не хватит Легко, только goto к этому ни сном ни духом. Цитата наверное на AVR это не очень актуальная проблемма, Мало памяти - мало проблем  Цитата но например на PC легко таким образом организовать переполнение Каким таким "таким образом"???
--------------------
Feci, quod potui, faciant meliora potentes
|
|
|
|
|
Mar 23 2007, 09:11
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610

|
Цитата(singlskv @ Mar 23 2007, 00:26)  goto не возвращает стек в исходное состояние, то есть если переменная была заведена на стеке то стек будет расходоваться зазря до выхода из функции Дело в том, что это вас интересовать не должно. Компилятор (ИАР особенно) - он грамотный, он посмотрит, как все выполняется, и переменную уберет (или не уберет) из стека в нужный момент. Обычно этот момент - всегда выход из функции, т.к. постоянно дергать стек вперед/назад довольно накладно. Так что пользуйте goto, пользуйте return, break, все будет ок, а вот ассемблеровкий ret поперк - это неправильно в любом случае. И вообще, правильно написаная программа должна компилироваться с макс. оптимизацией и работать. Если такого не происходит, ищите ошибки у себя (обычное дело - volatile забыли, вот как у вас - ret поперек всадили - это даже не ошибка, это... Ну не хочу плохие слова говорить  )
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
Mar 23 2007, 13:25
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(Alex ma @ Mar 21 2007, 20:03)  Есть глобальная структура с 4 переменными которые используются во функции MiDI По адресу 01F4.
Есть функция: void MiDI(void){ while(1){ здесь код. ret //выход }; }; Приведите весь код полностью, тогда все ясно будет.
|
|
|
|
|
Mar 24 2007, 01:06
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

|
Цитата(zltigo @ Mar 23 2007, 09:07)  А return, типа, возвращает, поскольку из функции выходит  . конечно, return; всегда востанавливает указатель стека  Цитата Весь обьем стека под локальные переменные выделяется сразу и соответственно освобождается сразу а не по кусочкам. Другого поведения для компиляторов с языков высокого уровня не наблюдал ни разу. Хорошо, сколько по вашему должен расходовать стека данных следующий код на хорошем компиляторе ? Код void func() { while(.......) { char str1[10]; ................. ................. }
while ( ........) { char str2[12]; .................. .................. } } 12 или 22 байта ? а если будут множественное goto причем как вперед так и назад ? Цитата Мало памяти - мало проблем  много регистров меньше проблем
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|