|
"Оптимизация" в WinAVR и как с этим бороться |
|
|
|
Nov 16 2011, 18:07
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Перейдя с ассемблера на WinAVR, невольно стал обращать на размер кода. Когда стал разбираться в конкретике генерируемого кода , хваленный на многих сайтах WinAVR обнажил свое несовершенство. Короче, программка : Код #include <avr/io.h> #include <inttypes.h>
#define Btn1 PB2 #define Btn2 PB3
#define KeyMask (1<<Btn1)|(1<<Btn2) #define sbi(p,b) (p |= (1<<b)) //Установить бит
volatile register int8_t Cnt asm("r19"); // фоновый счетчик volatile register int8_t a asm ("r16");
int main (void) { asm("nop"); a = 1;
while(1) { if (~(PINB)&(KeyMask)) { a |= 0x01; } if ((--Cnt)==0) { if (a==1 ) { a=0; sbi (PINB,PB2); } } } } Соответственно , полученный код: Код a = 1; ldi r16, 0x01
while(1) { [color="#FF00FF"]if (~(PINB)&(KeyMask)) in r24, 0x16 ldi r25, 0x00 com r24 com r25 andi r24, 0x0C andi r25, 0x00 or r24, r25 breq .+2[/color] { a |= 0x01; } ori r16, 0x01
[color="#FF0000"]if ((--Cnt)==0) mov r24, r19 subi r24, 0x01 mov r19, r24[/color] brne .-26 { if (a==1 ) cpi r16, 0x01 brne .-30 { a=0; ldi r16, 0x00
sbi (PINB,PB2); sbi 0x16, 2 rjmp .-36 Конструкцию if ((--Cnt)==0) выделенную крас.цветом может заменить всего одна машинная команда: dec r19! Вопрос: как заставить компилятор это делать ? Во втором случае: if (~(PINB)&(KeyMask)) , невижу смысла во втором парном регистре r25. Можно использовать "tst r24". Можно как нибудь с этим бороться ?! Не хочеться чтобы потом код получался неоправданно раздутым! Может быть стоит подождать другую версию компилятора (пользуюсь WinAVR-20100110) или уже пререходить на совсем другой ?
|
|
|
|
|
 |
Ответов
|
Nov 16 2011, 19:58
|

фанат дивана
     
Группа: Свой
Сообщений: 3 387
Регистрация: 9-08-07
Из: Уфа
Пользователь №: 29 684

|
Цитата(MaxiMuz @ Nov 17 2011, 00:07)  Перейдя с ассемблера на WinAVR, невольно стал обращать на размер кода. И зря. Если код помещается в чип и успевает сделать то, что должен, то какая разница, какого он размера? Цитата(MaxiMuz @ Nov 17 2011, 00:07)  Конструкцию if ((--Cnt)==0) выделенную крас.цветом может заменить всего одна машинная команда: dec r19! Вам же написали, что volatile register писать нельзя. Какие претензии? Что касается второго, то целочисленные константы по умолчанию имеют тип int. Попробуйте написать if (~(PINB)&((unsigned char)KeyMask)). ЗЫ. Выделение цветом не работает в блоке code, если сильно надо, то пользуйтесь блоком codebox - там вроде работает.
--------------------
Если бы я знал, что такое электричество...
|
|
|
|
|
Nov 18 2011, 09:00
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(AHTOXA @ Nov 16 2011, 22:58)  Вам же написали, что volatile register писать нельзя. Какие претензии? Это неправильное утверждение! Если из выражения "volatile register int8_t a asm ("r16");" убрать квалификатор volatile, то компилятор воообще обходит использование указанных регистров, используя свои. И хотя код получается короче, неизвестно как дальще поведет себя "оптимизатор" , если программа усложниться ! Цитата(neiver @ Nov 18 2011, 11:44)  Неа, результат другой: Код 6c: 86 b3 in r24, 0x16; 22 6e: 8c 70 andi r24, 0x0C; 12 70: 09 f4 brne .+2 ; 0x74 <main+0x8> На ЦЕЛУЮ команду меньше  На ОДНУ команду не считается  Так исторически сложилось что я проверяю на нулевой рез-т (не нажата не одна кнопка) и зацикливаю в начало
|
|
|
|
|
Nov 18 2011, 10:59
|

Гуру
     
Группа: Свой
Сообщений: 2 399
Регистрация: 10-05-06
Из: г. Новочеркасск
Пользователь №: 16 954

|
Цитата(MaxiMuz @ Nov 18 2011, 13:00)  На ОДНУ команду не считается Если Вы пытатесь заставить GCC генерить вместо if(!(PINB & KeyMask)) одну команду SBRS (или SBRC), то у Вас ничего не получится. Хотя Atmel и утверждает, что система команд AVR ориентированна на язык Си, то компиляторописатели так не считают... В Вашем первом и втором случаях компилятор действует по шаблону: 1) берёт значение на регистр r24 (то, что Вы расположили некую переменную в регистр - изменит только источник данных: значение будет взято из другого регистра или из ОЗУ): 2) на регистре r24 вычисляет выражение; 3) при необходимости, из регистра r24 сохраняет вычисленное выражение; 4) сравнивает значение выражения (регистр r24) с нулём... Только ну очень хороший оптимизатор заменит эту последовательность одной командой. GCC так сделать не сможет. Для AVR я не знаю компилятора, в который встроен настолько сильный оптимизатор, что сможет повторить Вашу программу на ассемблере. Имхо, если компилятор с ЯВУ генерит код "съедающий" на 10-15% больше ресурсов, чем аналогичная программа на ассемблере, на сегодняшний день - это ОЧЕНЬ хороший компилятор. Заметьте - программа(!!!, причем обычно довольно большая), а не отдельный оператор.
|
|
|
|
|
Nov 18 2011, 14:36
|
;
     
Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509

|
Цитата(Палыч @ Nov 18 2011, 13:59)  Имхо, если компилятор с ЯВУ генерит код "съедающий" на 10-15% больше ресурсов, чем аналогичная программа на ассемблере, на сегодняшний день - это ОЧЕНЬ хороший компилятор. Заметьте - программа(!!!, причем обычно довольно большая), а не отдельный оператор. ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. Еще - бывают напряги при работе с битовыми полями, сильное юзание регистра Х в адресных выражениях, не использует бит Т и не "подглядывает" за функциями, вызываемыми из прерываний - длинный контекст сохраняется. Больше никаких шероховатостей мною не замечено. А большую программу на асме еще написать надо, чтобы "сделать" современный Си на эти 10-15%.
|
|
|
|
|
Nov 18 2011, 16:17
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(_Pasha @ Nov 18 2011, 16:36)  ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. Ну, да. Но иногда такие места удаётся оформить в маленькие подпрограмки, которые вызывать в конце (в вумных книгах по программированию давно пишут, что не стоит бояться мелких подпрограмок :-) ). Тогда вкупе с --relax и получается слияние. Цитата(neiver @ Nov 18 2011, 16:45)  Подглядывает, еще как если функция inline. Вот еще до LTO нужно добраться, так там должно за всем подглядывать уметь. Вроде бы к 5-ой аврстудии компилятор идёт уже с LTO. Klen-овые сборки под Linux для ARM дают неплохой эффект. Для AVR у меня не запустились, что-то с библиотеками не срослось. Цитата(MaxiMuz @ Nov 18 2011, 18:06)  Что хотели написать то ? Возможно то, что без зауми с asm("r19") и прочими проявлениями детской болезни левизны dec сам бы появился, и заставлять не пришлось бы (ну тут не dec, но ни по размеру кода, ни по времени выполнения не отличается — возможно, и это сказать хотели): Код #include <avr/io.h> #include <inttypes.h>
#define Btn1 PB2 #define Btn2 PB3
#define KeyMask (1<<Btn1)|(1<<Btn2)
int main (void) { uint8_t Cnt = 0; uint8_t a = 0;
while(1) { if ( !(PINB & (KeyMask)) ) a |= 0x01; if ((--Cnt)==0) { if (a==1 ) { a=0; PINB |= (1 << 2); } } } } Код .global main .type main, @function main: /* prologue: function */ /* frame size = 0 */ ldi r18,lo8(0) .L8: ldi r25,lo8(0) .L7: in r24,54-32 andi r24,lo8(12) brne .L2 ori r25,lo8(1) .L2: subi r18,lo8(-(-1)) brne .L7 cpi r25,lo8(1) brne .L7 sbi 54-32,2 rjmp .L8
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 18 2011, 17:23
|
Местный
  
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123

|
Цитата(ReAl @ Nov 18 2011, 20:17)  Вот еще до LTO нужно добраться, так там должно за всем подглядывать уметь. Вроде бы к 5-ой аврстудии компилятор идёт уже с LTO. Klen-овые сборки под Linux для ARM дают неплохой эффект. Для AVR у меня не запустились, что-то с библиотеками не срослось. К сожалению, в avr-gcc LTO не работает. Компилятор к 5-ой аврстудии скомпилирован без поддержки LTO, я пытался скомпилировать avr-gcc сам со включеной LTO - не собрался, видимо чего-то в в AVR бекэнде не хватает.
|
|
|
|
|
Nov 20 2011, 11:58
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(neiver @ Nov 18 2011, 20:23)  К сожалению, в avr-gcc LTO не работает. Компилятор к 5-ой аврстудии скомпилирован без поддержки LTO, я пытался скомпилировать avr-gcc сам со включеной LTO - не собрался, видимо чего-то в в AVR бекэнде не хватает. У меня к сожелению, не достаточно глубокие познания в тонкостях компиляторов и знания абревиатур, да и практики маловато. Хотел узнать , что такое LTO ? Цитата(ReAl @ Nov 19 2011, 01:38)  Поверьте старому С-шнику, избегающему по мере возможности написания программ на асме -- Вам показалось. Что Вы проводили оптимизацию этой ассемблерной программы. Бегло просмотрел программу из архива, даже толком не вникая в алгоритмы. Просто мелкая местная оптимизация — и несколько десятков байт как с куста. А если ещё вникнуть в алгоритмы, то и того более найдётся. Примеры: Код #ifndef OPTIMISED sbrc ModeR,BitModeAlrm rjmp Begin sbrc ModeR,BitModeWtch rjmp Begin #else;;; -2 sbrs ModeR,BitModeAlrm sbrc ModeR,BitModeWtch rjmp Begin #endif Там таких два места. На этой мелочи — уже 4 байта. Я уважаю людей которые хорошо разбираются в С-ях !  Да, действительно я не достаточно тщательно провел оптимизацию данной программы ! И в приведнном примере , я возможно проглядел, либо просто не стал обращать внимание на эти мелочи ... п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру. Цитата(ReAl @ Nov 19 2011, 01:38)  Любой уважающий себя С-компилятор покраснел бы от стыда за такой код: Код ; Определение интервала 1 #ifndef OPTIMISED ; if ( MemdP <= Thr_AdP ) goto TCAdi11; else goto TCAdi12; cpi MemdPH,Thr_AdPH brcs TCAdi11 brne TCAdi12 cpi MemdPL,Thr_AdPL brcs TCAdi11 brne TCAdi12 #else;;; -4 bytes ; if MemdP >= (Thr_AdP + 1) ) goto TCAdi12 ldi temp, high( Thr_AdP + 1 ) cpi MemdPL, low( Thr_AdP + 1) cpc MemdPH, temp brcc TCAdi12 #endif Код #ifndef OPTIMISED ; if ( MemdP <= DeltaT ) goto TCA12; esle goto TCA11; cp MemdPH,DeltaTH brcs TCA12 brne TCA11 cp MemdPL,DeltaTL brcs TCA12 brne TCA11 #else ;;; -6 ; if ( DeltaT >= MemdP ) goto TCA11; cp DeltaTL,MemdPL cpc DeltaTH,MemdPH brcc TCA11 #endif И таких мест там не одно. Суть правильная, только ваш оптимизатор почемуто в метках переходов ошибся ! при условии С=0 должна выполняться какраз противоположная ветвь ! Вот так доверяй потом оптимизаторам !! И в данном куске, почему я сначала старшие байты решил проверять : хотел ускорить алгоритм проверки. Хотя сейчас понимаю что это не к чему было. И всеже вернусь к использованию регистровых глобальных перемнных. В теме: заголовок"Второй раз повторяю, GCC не поддерживает volatile register переменные. Не поддерживает - это значит что нет гарантии что любой код использующий volatile register переменные будет работать при любом уровне оптимизации. К сожалению варинг сообщающий об этом пропал где-то в 2005 году и если я правильно понял его вернули в феврале 2008. Попробуйте откомпилировать тестовый пример с "volatile register" GCC 4.4 с клюем -Wall. Или с ключом -Wvolatile-register-var на 4.3. Анатолий. " были упомянуты ключики. Я не нашел в дока назначение этих ключей, плохо ориентируюсь описании WinAVR. Есть ли возможность отключить в опциях использование компилятором конкретных регистров ?
Сообщение отредактировал MaxiMuz - Nov 20 2011, 11:15
|
|
|
|
|
Nov 20 2011, 12:23
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(MaxiMuz @ Nov 20 2011, 12:55)  Хотел узнать , что такое LTO ? Link-Time-Optimiser Зачатки его есть и в нынешнем линкере, ключ --relax. Это, например, превращение линкером длинного вызова в короткий. На этапе компиляции ещё неизвестно, насколько близко лягут куски из разных файлов и на больших кристаллах компилятром используется только длинный. LTO делает полную оптимизацию, зная уже всё о линкуемой программе (включая устройство библиотечных функций, если они были скомпилировані с соо-тветствующим ключом). Цитата(MaxiMuz @ Nov 20 2011, 12:55)  Да, действительно я не достаточно тщательно провел оптимизацию данной программы ! И в приведнном примере , я возможно проглядел, либо просто не стал обращать внимание на эти мелочи ... Ну там дальше и не такие мелочи на cp/cpc набегают, как тут на пропусках. Цитата(MaxiMuz @ Nov 20 2011, 12:55)  п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру. И какой смысл после этого было говорить, что "на ассемблере влезла одна мелодия и то после оптимизации, а С и одна не влезла бы" ? ;-) У С по длине выигрывает не любая ассемблерная реализация — только потому, что она ассемблерная  — а только действительно вылизанная. Прикидочно, оценивая возможное ужатие Вашего кода байт на 150-200, — тут и С-шная реализация должна легко влезть. Цитата(MaxiMuz @ Nov 20 2011, 13:58)  Суть правильная, только ваш оптимизатор почемуто в метках переходов ошибся ! при условии С=0 должна выполняться какраз противоположная ветвь ! Ну там в одном из мест я для нужной нестрогости сравнивания поменял порядок операндов, мог забыть про смену полярности перехода. Это не важно, ошибки в коде любой длины бывают. Главное то, что код можно написать короче. Там ещё ошибки есть, например, в одном из мест надо так: Код cpi temp2, Edata1 + MaxCount*2-1 Это до меня уже в субботу утром, в метро по дороге на работу в дрёме дошло. Отмазки: 1) Ну дак в пол второго ночи и наспех (вставать-то в шесть), да копипастом-редактированием (из головы я бы сразу правильно писал) и не такого наворотить можно 2) А С-компилятор и не ошибся бы с "полярностью" перехода. Цитата(MaxiMuz @ Nov 20 2011, 13:58)  Есть ли возможность отключить в опциях использование компилятором конкретных регистров ? -ffixed-reg, например -ffixed-reg=r2 Только нужно быть уверенным, что библиотека тоже этот регистр не использует.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 23 2011, 11:30
|

Местный
  
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658

|
Цитата(ReAl @ Nov 20 2011, 15:23)  ........................................ -ffixed-reg, например -ffixed-reg=r2 Только нужно быть уверенным, что библиотека тоже этот регистр не использует. После вставики в Makefile Код CFLAGS += -ffixed-reg=r16 CFLAGS += -ffixed-reg=r18 Компилятор выдал ошибку: Код cc1.exe: warning: unknown register name: reg=r16 cc1.exe: warning: unknown register name: reg=r18 Что я не так делаю ? И где можно найти описание всех ключей компилятора GCC
|
|
|
|
Сообщений в этой теме
MaxiMuz "Оптимизация" в WinAVR и как с этим бороться Nov 16 2011, 18:07 Палыч Цитата(MaxiMuz @ Nov 16 2011, 22:07) хвал... Nov 16 2011, 18:45 MaxiMuz Цитата(Палыч @ Nov 16 2011, 21:45) А, вот... Nov 16 2011, 19:19  Палыч Цитата(MaxiMuz @ Nov 16 2011, 23:19) KeyM... Nov 16 2011, 20:10   MaxiMuz Цитата(Палыч @ Nov 16 2011, 23:10) Почему... Nov 16 2011, 21:06    aaarrr Цитата(MaxiMuz @ Nov 17 2011, 01:06) or ... Nov 16 2011, 21:19     MaxiMuz Цитата(aaarrr @ Nov 17 2011, 00:19) Это о... Nov 17 2011, 15:19      Палыч Цитата(MaxiMuz @ Nov 17 2011, 19:19) ... ... Nov 17 2011, 17:42      AHTOXA Цитата(MaxiMuz @ Nov 17 2011, 21:19) А ес... Nov 17 2011, 17:47      _Pasha Цитата(MaxiMuz @ Nov 17 2011, 19:19) Код ... Nov 18 2011, 06:25    neiver Цитата(_Pasha @ Nov 18 2011, 18:36) и не ... Nov 18 2011, 14:45     demiurg_spb Паша верно перечислил основные недочёты avr-gcc, с... Nov 18 2011, 17:13          ReAl Тьху, ну конечно, -ffixed-reg
Что-то меня на = пот... Nov 23 2011, 21:19         AHTOXA КодCFLAGS += -ffixed-r16
CFLAGS += -ffixed-r18 Nov 23 2011, 14:40   MaxiMuz Цитата(Палыч @ Nov 18 2011, 13:59) Если В... Nov 18 2011, 16:06    ReAl Цитата(MaxiMuz @ Nov 18 2011, 18:06) боль... Nov 18 2011, 22:38  Сергей Борщ QUOTE (MaxiMuz @ Nov 18 2011, 12:00) Это ... Nov 18 2011, 11:54 ReAl Цитата(MaxiMuz @ Nov 16 2011, 20:07) Код#... Nov 16 2011, 21:53 Genadi Zawidowski Код#define KeyMask (1<<Btn1)|... Nov 17 2011, 01:30 neiver Мда, можно вытащить ассемблерщика из ассемблера, н... Nov 17 2011, 08:19 Палыч Цитата(neiver @ Nov 17 2011, 12:19) integ... Nov 17 2011, 09:27 neiver Я к чему, тут про целочисленное расширение намекаю... Nov 18 2011, 05:25 MaxiMuz neiver , _Pasha да действительно, можно и так напи... Nov 18 2011, 08:38 neiver Цитата(MaxiMuz @ Nov 18 2011, 12:38) neiv... Nov 18 2011, 08:44 neiver GCC прекрасно может сгенерировать одну команду sbi... Nov 18 2011, 11:07 Палыч Цитата(neiver @ Nov 18 2011, 15:07) GCC п... Nov 18 2011, 11:17 ReAl Жаль. Nov 18 2011, 19:58 MaxiMuz Спасибо за ответы !
Опять я возвращаюсь к св... Nov 25 2011, 08:40 Сергей Борщ QUOTE (MaxiMuz @ Nov 25 2011, 11:40) Хоте... Nov 25 2011, 09:27  MaxiMuz Цитата(Сергей Борщ @ Nov 25 2011, 12:27) ... Nov 25 2011, 12:07   AHTOXA Цитата(MaxiMuz @ Nov 25 2011, 18:07) Вопр... Nov 25 2011, 14:16    ReAl Цитата(AHTOXA @ Nov 25 2011, 16:16) Какой... Nov 25 2011, 14:35     AHTOXA По-моему, на этот вопрос тоже уже ответили, и не р... Nov 25 2011, 19:17 ReAl Провёл маленький эксперимент.
Убрал все эти regist... Nov 25 2011, 20:32 MaxiMuz AHTOXA с вами не поспоришь
ReAl По сути , кусок... Nov 28 2011, 10:59 ReAl Цитата(MaxiMuz @ Nov 28 2011, 12:59) подо... Nov 28 2011, 14:16 sigmaN перед main воткните __attribute__ ((noreturn));
h... Nov 28 2011, 19:40 MaxiMuz Цитата(sigmaN @ Nov 28 2011, 22:40) перед... Jan 23 2012, 09:15 ReAl Для этого в AVR-GCC уже давно есть OS_main и OS_ta... Nov 28 2011, 20:17 sigmaN ну или так, да.
а ещё я из исходников библиотеки ... Nov 28 2011, 22:10 ILYAUL Цитата(sigmaN @ Nov 29 2011, 02:10) ну ил... Nov 29 2011, 04:15  ARV Цитата(ILYAUL @ Nov 29 2011, 08:15) ИМХО ... Jan 23 2012, 09:53 MaxiMuz При использовании int OS_main (void) компилятор вы... Jan 23 2012, 14:50 sigmaN warning это не error и по идее не должен приводить... Jan 24 2012, 02:07 MaxiMuz Цитата(sigmaN @ Jan 24 2012, 05:07) warni... Feb 2 2012, 11:49 _Pasha Таварисч не панимаит.
Кодint main(void) __... Feb 2 2012, 12:16 MaxiMuz Цитата(_Pasha @ Feb 2 2012, 15:16) Тавари... Feb 3 2012, 10:42  Сергей Борщ QUOTE (MaxiMuz @ Feb 3 2012, 12:42) Да... Feb 3 2012, 11:08 MaxiMuz Доброго времяни суток!
Не стал создавать отдел... Oct 16 2012, 18:35 Палыч Цитата(MaxiMuz @ Oct 16 2012, 22:35) здес... Oct 17 2012, 06:15  MaxiMuz Цитата(Палыч @ Oct 17 2012, 09:15) Это - ... Oct 17 2012, 12:11   Сергей Борщ В этом стандарте операция "&" выполн... Oct 17 2012, 12:59   Палыч Цитата(MaxiMuz @ Oct 17 2012, 16:11) стан... Oct 17 2012, 13:04 Genadi Zawidowski Используйте компилятор поновее (avr-gcc 4.7.2, avr... Oct 16 2012, 19:26
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|