|
|
|
"Оптимизация" в 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:19
|
Местный
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658
|
Цитата(Палыч @ Nov 16 2011, 21:45) А, вот тут - "неча на зеркало пенять..." (т.е. не нужно "мешать" восьми- и шестнадцатибитные операнды). а где вы увидели 16ти битные операнды ? PINB читается как 8ми битные KeyMask тоже 8мь бит !
|
|
|
|
|
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 16 2011, 21:06
|
Местный
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658
|
Цитата(Палыч @ Nov 16 2011, 23:10) Почему? Обоснуйте. смотрите по коду, предпоследния команда: or r24, r25 я не думаю что старший байт с младшим компилятор сталбы склеивать ! Кстати , можно проверить по присваиванию
|
|
|
|
|
Nov 16 2011, 21:53
|
Нечётный пользователь.
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417
|
Цитата(MaxiMuz @ Nov 16 2011, 20:07) Код #define KeyMask (1<<Btn1)|(1<<Btn2) KeyMask - результат вычисления выражения (пусть и в compile-time). По стандарту языка С имеет тип как минимум int. Дальше у gcc недооптимизация, спору нет. Но он обязан был сначала всё делать в int-ах и только потом натравить оптимизатор.
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Nov 17 2011, 08:19
|
Местный
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123
|
Мда, можно вытащить ассемблерщика из ассемблера, но... По поводу регистровых переменных. В них практически никогда нет реальной необходимости, особенно в достаточно сложных программах. Мнимая выгода из-за отсутствий-загрузок выгрузок из/в память, с лихвой перекрываются необходимостью тасовать и сохранять регистры, например, для вызова функций и тупяками компилятора из-за того, что он не может использовать регистры, занятые под эти переменные, так как умеет. Модификатор volatile с регистровыми переменными, как уже сказали, не работает. Если возникает реальзая ситуация, когда программа относительно проста и нехватает нескользих тактов для выполнения критического участка, то наверное имеет смысл переписать этот критический участок, а то и всю программу на ассемблере. Код if (~(PINB)&(KeyMask)) В Си есть такая штука - целочисленное расширение называется (integer propagation). Рекомендую погуглить и почитать, что это такое, многоя станет понятно.
|
|
|
|
|
Nov 17 2011, 15:19
|
Местный
Группа: Участник
Сообщений: 253
Регистрация: 15-04-10
Из: Волгоград
Пользователь №: 56 658
|
Цитата(aaarrr @ Nov 17 2011, 00:19) Это обычная проверка пары регистров на 0. Как это компилятор резервирует старший байт , а потом проверяет младший со старшим ? Как то не логично получается ! AHTOXA, Пробывал я выражение : if (~(PINB)&((unsigned char)KeyMask)) - Результат абсолютно тот же, и скобки как говорили в #define я поставил, один хрен ! Попробывал предварительное присваивание константы в регистр : Код volatile register int8_t Cnt asm("r19"); // фоновый счетчик volatile register int8_t a asm ("r16"); volatile register int8_t b asm ("r17");
int main (void) { asm("nop"); a = 1; b=KeyMask; while(1) { if (~(PINB)&(b)) { a |= 0x01; } if ((--Cnt)==0) { if (a==1 ) { a=0; b |= 0x08; sbi (PINB,PB2); } } } } Тут Вообще "Оптимизатор" показал чудеса !!! Цитата(Genadi Zawidowski @ Nov 17 2011, 04:30) Назначение регистров для переменных ОЧЕНЬ сильно мешает оптимизации. Если рассуждать как вы , то можно сказать и любая программа написанная в Си мешает оптимизации!!! Вы еще бы посоветовали на Ассемблере писать Цитата(AHTOXA @ Nov 16 2011, 22:58) И зря. Если код помещается в чип и успевает сделать то, что должен, то какая разница, какого он размера? А если не помещается, и делает с большими задержками по времяни ? Цитата(AHTOXA @ Nov 16 2011, 22:58) ЗЫ. Выделение цветом не работает в блоке code, если сильно надо, то пользуйтесь блоком codebox - там вроде работает. Кстати , а что за блок codebox ? я про него ничего не слышал Во втором случае, все просто ! Я заранее знал решение, и хотел посмотреть что вы скажите (может чего новое) Проблемка решается заменой конструкции: if (~(PINB)&(KeyMask)) на несколько команд: b=~(PINB); b&=KeyMask; if ( { ......} Код сокращается всего лишь до: Код IN R24,0x16 COM R24 ANDI R24,0x0C BREQ PC+0x02 А вот с первой проблемой мусорных присваиваний , похоже все мрачно !
|
|
|
|
|
Nov 18 2011, 05:25
|
Местный
Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123
|
Я к чему, тут про целочисленное расширение намекаю? Компилятор в данном случае делает ровно, то, что ему сказано. В вашем выражении нужна не битовая инверсия, а логическая: Код #define KeyMask ((1<<Btn1)|(1<<Btn2)) ... if( ! (PINB & KeyMask) ) { ... } Посмотрите, и почувствуйте разницу.
|
|
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|