реклама на сайте
подробности

 
 
> "Оптимизация" в WinAVR и как с этим бороться
MaxiMuz
сообщение Nov 16 2011, 18:07
Сообщение #1


Местный
***

Группа: Участник
Сообщений: 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) или уже пререходить на совсем другой ?
Go to the top of the page
 
+Quote Post
5 страниц V   1 2 3 > »   
Start new topic
Ответов (1 - 63)
Палыч
сообщение Nov 16 2011, 18:45
Сообщение #2


Гуру
******

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



Цитата(MaxiMuz @ Nov 16 2011, 22:07) *
хваленный на многих сайтах WinAVR обнажил свое несовершенство.
В большенстве трансляторов с ЯВУ можно найти "несовершенство"...

Цитата(MaxiMuz @ Nov 16 2011, 22:07) *
Во втором случае: if (~(PINB)&(KeyMask)) , невижу смысла во втором парном регистре r25. Можно использовать "tst r24". Можно как нибудь с этим бороться ?!
А, вот тут - "неча на зеркало пенять..." (т.е. не нужно "мешать" восьми- и шестнадцатибитные операнды).
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 16 2011, 19:19
Сообщение #3


Местный
***

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



Цитата(Палыч @ Nov 16 2011, 21:45) *
А, вот тут - "неча на зеркало пенять..." (т.е. не нужно "мешать" восьми- и шестнадцатибитные операнды).

а где вы увидели 16ти битные операнды ?
PINB читается как 8ми битные
KeyMask тоже 8мь бит !
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 16 2011, 19:58
Сообщение #4


фанат дивана
******

Группа: Свой
Сообщений: 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 - там вроде работает.


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
Палыч
сообщение Nov 16 2011, 20:10
Сообщение #5


Гуру
******

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



Цитата(MaxiMuz @ Nov 16 2011, 23:19) *
KeyMask тоже 8мь бит !
Почему? Обоснуйте.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 16 2011, 21:06
Сообщение #6


Местный
***

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



Цитата(Палыч @ Nov 16 2011, 23:10) *
Почему? Обоснуйте.

смотрите по коду, предпоследния команда:
or r24, r25
я не думаю что старший байт с младшим компилятор сталбы склеивать !
Кстати , можно проверить по присваиванию
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Nov 16 2011, 21:19
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(MaxiMuz @ Nov 17 2011, 01:06) *
or r24, r25
я не думаю что старший байт с младшим компилятор сталбы склеивать !

Это обычная проверка пары регистров на 0.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 16 2011, 21:53
Сообщение #8


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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-ах и только потом натравить оптимизатор.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Nov 17 2011, 01:30
Сообщение #9


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Код
#define  KeyMask (1<<Btn1)|(1<<Btn2)


А скобочки для защиты от подводных граблей не хотите поставить?

Назначение регистров для переменных ОЧЕНЬ сильно мешает оптимизации.
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 17 2011, 08:19
Сообщение #10


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Мда, можно вытащить ассемблерщика из ассемблера, но...
По поводу регистровых переменных. В них практически никогда нет реальной необходимости, особенно в достаточно сложных программах. Мнимая выгода из-за отсутствий-загрузок выгрузок из/в память, с лихвой перекрываются необходимостью тасовать и сохранять регистры, например, для вызова функций и тупяками компилятора из-за того, что он не может использовать регистры, занятые под эти переменные, так как умеет. Модификатор volatile с регистровыми переменными, как уже сказали, не работает. Если возникает реальзая ситуация, когда программа относительно проста и нехватает нескользих тактов для выполнения критического участка, то наверное имеет смысл переписать этот критический участок, а то и всю программу на ассемблере.
Код
if (~(PINB)&(KeyMask))

В Си есть такая штука - целочисленное расширение называется (integer propagation). Рекомендую погуглить и почитать, что это такое, многоя станет понятно.

Go to the top of the page
 
+Quote Post
Палыч
сообщение Nov 17 2011, 09:27
Сообщение #11


Гуру
******

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



Цитата(neiver @ Nov 17 2011, 12:19) *
integer propagation

Integer promotion
Но, в данном случае - это не оно. Имеет место банальное использование в выражении операндов двух разных типов, "меньший" из которых приводится к "большему".
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 17 2011, 15:19
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 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);
        }
    }
}
}

Тут Вообще "Оптимизатор" показал чудеса !!! sm.gif

Цитата(Genadi Zawidowski @ Nov 17 2011, 04:30) *
Назначение регистров для переменных ОЧЕНЬ сильно мешает оптимизации.

Если рассуждать как вы , то можно сказать и любая программа написанная в Си мешает оптимизации!!!
Вы еще бы посоветовали на Ассемблере писать sm.gif

Цитата(AHTOXA @ Nov 16 2011, 22:58) *
И зря. Если код помещается в чип и успевает сделать то, что должен, то какая разница, какого он размера?

А если не помещается, и делает с большими задержками по времяни ?


Цитата(AHTOXA @ Nov 16 2011, 22:58) *
ЗЫ. Выделение цветом не работает в блоке code, если сильно надо, то пользуйтесь блоком codebox - там вроде работает.

Кстати , а что за блок codebox ?
я про него ничего не слышал

Во втором случае, все просто ! sm.gif Я заранее знал решение, и хотел посмотреть что вы скажите (может чего новое)
Проблемка решается заменой конструкции:
if (~(PINB)&(KeyMask))

на несколько команд:
b=~(PINB);
b&=KeyMask;
if (cool.gif
{ ......}

Код сокращается всего лишь до:
Код
IN      R24,0x16
COM     R24          
ANDI    R24,0x0C
BREQ    PC+0x02


А вот с первой проблемой мусорных присваиваний , похоже все мрачно ! sad.gif
Go to the top of the page
 
+Quote Post
Палыч
сообщение Nov 17 2011, 17:42
Сообщение #13


Гуру
******

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



Цитата(MaxiMuz @ Nov 17 2011, 19:19) *
... похоже все мрачно !
Если Вы считали, что компилятор выдаст точную копию Вашей программы на ассемблере, то, разочарую Вас, - такого не будет: компилятор всё-таки действует по некоему шаблону, что не всегда даёт "хороший" код. Иногда компилятору можно в его работе помочь. Atmel по этому поводу выпустил AppNote AVR035.
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 17 2011, 17:47
Сообщение #14


фанат дивана
******

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



Цитата(MaxiMuz @ Nov 17 2011, 21:19) *
А если не помещается, и делает с большими задержками по времяни ?
Вот когда упрётесь в такую ситуацию, тогда и начинайте оптимизацию sm.gif
Цитата(MaxiMuz @ Nov 17 2011, 21:19) *
Кстати , а что за блок codebox ?
я про него ничего не слышал

У меня он слева, под смайликами. Хотя можно и просто руками поменять [соde]lalala[/соde] на [соdebox]lalala[/соdebox]. Хотя это наверное зависит от применяемого редактора (правая верхняя кнопка : ).


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 18 2011, 05:25
Сообщение #15


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Я к чему, тут про целочисленное расширение намекаю? Компилятор в данном случае делает ровно, то, что ему сказано. В вашем выражении нужна не битовая инверсия, а логическая:
Код
#define  KeyMask ((1<<Btn1)|(1<<Btn2))
...
if( ! (PINB & KeyMask) )
{
        ...
}

Посмотрите, и почувствуйте разницу.
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Nov 18 2011, 06:25
Сообщение #16


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Цитата(MaxiMuz @ Nov 17 2011, 19:19) *
Код сокращается всего лишь до:

Так не полагайтесь на CSE там, где это не надо. laughing.gif
Поясню: если в выражении присутствует хоть одна volatile-переменная, она все равно испортит общую оптимизацию выражения. Надо ж думать, прежде чем писать!

И смысла в if (~(PINB)&(KeyMask)) много меньше, чем в if( ! (PINB & KeyMask) ). Ой, уже опередили.

Сообщение отредактировал _Pasha - Nov 18 2011, 06:26
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 18 2011, 08:38
Сообщение #17


Местный
***

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



neiver , _Pasha да действительно, можно и так написать, результат будут тотже что и в моем варианте ! С этим более менее понятно.
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 18 2011, 08:44
Сообщение #18


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Цитата(MaxiMuz @ Nov 18 2011, 12:38) *
neiver , _Pasha да действительно, можно и так написать, результат будут тотже что и в моем варианте ! С этим более менее понятно.

Неа, результат другой:
Код
6c:    86 b3           in    r24, 0x16; 22
  6e:    8c 70           andi    r24, 0x0C; 12
  70:    09 f4           brne    .+2      ; 0x74 <main+0x8>

На ЦЕЛУЮ команду меньше sm.gif
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 18 2011, 09:00
Сообщение #19


Местный
***

Группа: Участник
Сообщений: 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>

На ЦЕЛУЮ команду меньше sm.gif

На ОДНУ команду не считается sm.gif
Так исторически сложилось что я проверяю на нулевой рез-т (не нажата не одна кнопка) и зацикливаю в начало
Go to the top of the page
 
+Quote Post
Палыч
сообщение Nov 18 2011, 10:59
Сообщение #20


Гуру
******

Группа: Свой
Сообщений: 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% больше ресурсов, чем аналогичная программа на ассемблере, на сегодняшний день - это ОЧЕНЬ хороший компилятор. Заметьте - программа(!!!, причем обычно довольно большая), а не отдельный оператор.
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 18 2011, 11:07
Сообщение #21


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



GCC прекрасно может сгенерировать одну команду sbis (или sbiс), но не когда в маске установлены два бита:
#define KeyMask ((1<<Btn1)|(1<<Btn2))
Оставим обин бит и будет вам счастье:
Код
    if(!(PINB&KeyMask))
  6c:    b2 9b           sbis    0x16, 2; 22

А если в маске несколько единичных бит, то только честно сравнивать с нулем.
Go to the top of the page
 
+Quote Post
Палыч
сообщение Nov 18 2011, 11:17
Сообщение #22


Гуру
******

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



Цитата(neiver @ Nov 18 2011, 15:07) *
GCC прекрасно может сгенерировать одну команду sbis (или sbiс), но не когда в маске установлены два бита
Да, согласен...
Я собирался написать об операторе if ((--Cnt)==0) и команде DEC, но обширное обсуждение в этой теме оператора if(!(PINB & KeyMask)) сбило с мысли...
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 18 2011, 11:54
Сообщение #23


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (MaxiMuz @ Nov 18 2011, 12:00) *
Это неправильное утверждение!
Вдумайтесь, что вы написали. Авторы компилятора указывают, что использовать volatile и register совместно нельзя. Вы обвиняете их во лжи. Достаточно смело, но бесперспективно - во-первых авторы компилятора не читают этот форум, а во-вторых - ну, продолжайте бороться с ветряными мельницами. Напоминает FAQ про яйцо и микроволновку.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Nov 18 2011, 14:36
Сообщение #24


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



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

ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. Еще - бывают напряги при работе с битовыми полями, сильное юзание регистра Х в адресных выражениях, не использует бит Т и не "подглядывает" за функциями, вызываемыми из прерываний - длинный контекст сохраняется. Больше никаких шероховатостей мною не замечено. А большую программу на асме еще написать надо, чтобы "сделать" современный Си на эти 10-15%.
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 18 2011, 14:45
Сообщение #25


Местный
***

Группа: Участник
Сообщений: 214
Регистрация: 22-03-10
Из: Саратов
Пользователь №: 56 123



Цитата(_Pasha @ Nov 18 2011, 18:36) *
и не "подглядывает" за функциями, вызываемыми из прерываний - длинный контекст сохраняется.

Подглядывает, еще как если функция inline.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 18 2011, 16:06
Сообщение #26


Местный
***

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



Цитата(Палыч @ Nov 18 2011, 13:59) *
Если Вы пытатесь заставить GCC генерить вместо if(!(PINB & KeyMask)) одну команду SBRS (или SBRC), то у Вас ничего не получится. .....

с этим место собственно я разобрался.

Цитата(_Pasha @ Nov 18 2011, 17:36) *
ГЦЦ не умеет сливать ПП из разных точек входа в поток с одной командой возврата. .....

Не понятно о чем вы говорите

Цитата(_Pasha @ Nov 18 2011, 17:36) *
...... А большую программу на асме еще написать надо, чтобы "сделать" современный Си на эти 10-15%.

большая - маленькая зависит от типа МК. Привожу конкретный пример:
Код
http://www.radio.ru/archive/2010/07/a19.shtml

программка писалась на асме под ATtiny2313, нехватило памяти программ под вторую таблицу мелодий для звонка. Если бы тогда писал на Си то вообще не хватилобы памяти на одну таблицу ! Это при том что я еще проводил оптимизацию программы в ассеблере sm.gif

Цитата(Палыч @ Nov 18 2011, 14:17) *
Да, согласен...
Я собирался написать об операторе if ((--Cnt)==0) и команде DEC, но обширное обсуждение в этой теме оператора if(!(PINB & KeyMask)) сбило с мысли...

Что хотели написать то ?
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 18 2011, 16:17
Сообщение #27


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 18 2011, 17:13
Сообщение #28


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Паша верно перечислил основные недочёты avr-gcc, сравнив видимо с IAR, ну так и всё же IAR коммерческий продукт.
И кому так важны эти последние 5-10 % упущенной выгоды используют IAR.
А большинству это не принципиально и оно это большинство получает кайф от гнутого софта (и это не шутка).
Топик-стартеру прежде всего стоит перестать считать себя умнее компилятора и просто методично читать доки по Си и по компилятору. Глядишь через годик-другой всё наладится в голове и все нынешние "претензии" будут восприниматься с улыбкой.
ЗЫЖ приводить приемеры как мол круто я подковал блоху в позапрошлом столетии - это по меньшей мере не актуально и никого давно уже не удивляет.


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
neiver
сообщение Nov 18 2011, 17:23
Сообщение #29


Местный
***

Группа: Участник
Сообщений: 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 бекэнде не хватает.
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 18 2011, 19:58
Сообщение #30


Нечётный пользователь.
******

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



Жаль.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 18 2011, 22:38
Сообщение #31


Нечётный пользователь.
******

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



Цитата(MaxiMuz @ Nov 18 2011, 18:06) *
большая - маленькая зависит от типа МК. Привожу конкретный пример:
Код
http://www.radio.ru/archive/2010/07/a19.shtml

программка писалась на асме под ATtiny2313, нехватило памяти программ под вторую таблицу мелодий для звонка. Если бы тогда писал на Си то вообще не хватилобы памяти на одну таблицу ! Это при том что я еще проводил оптимизацию программы в ассеблере sm.gif
Поверьте старому С-шнику, избегающему по мере возможности написания программ на асме -- Вам показалось.
Что Вы проводили оптимизацию этой ассемблерной программы.
Бегло просмотрел программу из архива, даже толком не вникая в алгоритмы. Просто мелкая местная оптимизация — и несколько десятков байт как с куста. А если ещё вникнуть в алгоритмы, то и того более найдётся.
Примеры:
Код
#ifndef OPTIMISED
     sbrc ModeR,BitModeAlrm
     rjmp Begin
     sbrc ModeR,BitModeWtch
     rjmp Begin
#else;;; -2
     sbrs ModeR,BitModeAlrm
     sbrc ModeR,BitModeWtch
     rjmp Begin
#endif
Там таких два места. На этой мелочи — уже 4 байта.

Любой уважающий себя С-компилятор покраснел бы от стыда за такой код:
Код
; Определение интервала 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
И таких мест там не одно.
Тут вообще что-то странное было.
CODE
;_________ Запись таблицы регистрации нажатий в EEPROM
;*
;*
CLI
push temp2
push ZL
push ZH
#ifndef OPTIMISED
clr ZL
clr ZH
b4: mov temp,ZL
ldi temp2,low(Edata1)
add temp,temp2
OUT EEAR,temp
ldi temp2,low(data1)
add ZL,temp2
LD temp,Z
sub ZL,temp2
OUT EEDR,temp
SBI EECR,EEMPE;
SBI EECR,EEPE
b5: sbic EECR,EEPE
rjmp b5
cpi ZL,MaxCount*2-1
breq b6
ld temp,Z+
rjmp b4
b6: ldi temp,low(EMrk1)
OUT EEAR,temp
ldi temp,0xab
OUT EEDR,temp
SBI EECR,EEMPE;
SBI EECR,EEPE

#else ;;; -14b

ldi ZL, low(data1)
clr ZH
ldi temp2, Edata1
b4:
ld temp, Z+
rcall WrEE
inc temp2
cpi temp2, MaxCount*2-1
brne b4
b6: ldi temp2,low(EMrk1)
ldi temp,0xab
rcall WrEE
#endif

pop ZH
pop ZL
pop temp2
SEI

m9:
CLR EnGen
clr count
m11:
;______ Задержка
ldi temp,ZDelayL
mov CL,temp
rcall DelayTime
Begin__:
rjmp Begin

#ifdef OPTIMISED
WrEE:
OUT EEAR,temp2
OUT EEDR,tempЯ
SBI EECR,EEMPE;
SBI EECR,EEPE
WrEEw: sbic EECR,EEPE
rjmp WrEEw
ret
#endif
Эта запись вообще дважды повторяется, в слегка разном окружении. Её всю в подпрограмму надо пустить.
Ещё tiny2313 есть регистры GPIOR, аж три штуки. Все флаги успешно летят туда без увеличения объёма кода с незначителным увеличением времени. Освобождается два регистра, причём "верхних". Явно где-то поможет сократить код.
Я бы постарался выделить регистровую пару Y под указатель на блок данных в DSEG, заменив все LDS/STS на LDD/STD. Ещё так на глаз минимум полсотни байт.
Напоминаю — это всё не особо вникая в суть кода.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 20 2011, 11:58
Сообщение #32


Местный
***

Группа: Участник
Сообщений: 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 байта.

Я уважаю людей которые хорошо разбираются в С-ях ! sm.gif
Да, действительно я не достаточно тщательно провел оптимизацию данной программы ! И в приведнном примере , я возможно проглядел, либо просто не стал обращать внимание на эти мелочи ...

п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру.

Цитата(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
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 20 2011, 12:23
Сообщение #33


Нечётный пользователь.
******

Группа: Свой
Сообщений: 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) *
п.с. а про код "записи в ЕЕПРОМ" я прекрасно знал , просто в этой программе не стал его выделять в отдельную процедуру.

И какой смысл после этого было говорить, что "на ассемблере влезла одна мелодия и то после оптимизации, а С и одна не влезла бы" ? ;-)
У С по длине выигрывает не любая ассемблерная реализация — только потому, что она ассемблерная biggrin.gif — а только действительно вылизанная.
Прикидочно, оценивая возможное ужатие Вашего кода байт на 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
Только нужно быть уверенным, что библиотека тоже этот регистр не использует.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 23 2011, 11:30
Сообщение #34


Местный
***

Группа: Участник
Сообщений: 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
Go to the top of the page
 
+Quote Post
demiurg_spb
сообщение Nov 23 2011, 13:39
Сообщение #35


неотягощённый злом
******

Группа: Свой
Сообщений: 2 746
Регистрация: 31-01-08
Из: Санкт-Петербург
Пользователь №: 34 643



Цитата(MaxiMuz @ Nov 23 2011, 15:30) *
где можно найти описание всех ключей компилятора GCC
Как всегда в гугле, забив в строке поиска:
gcc optimization options


--------------------
“Будьте внимательны к своим мыслям - они начало поступков” (Лао-Цзы)
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 23 2011, 14:40
Сообщение #36


фанат дивана
******

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



Код
CFLAGS    += -ffixed-r16
CFLAGS    += -ffixed-r18


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 23 2011, 21:19
Сообщение #37


Нечётный пользователь.
******

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



Тьху, ну конечно, -ffixed-reg
Что-то меня на = потянуло :-)

Цитата(demiurg_spb @ Nov 23 2011, 15:39) *
Как всегда в гугле, забив в строке поиска:
gcc optimization options
Если бы гугл умел посылать пользователя на его локальный диск в

file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/index.html

в частности,
file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/AVR-options.html
file:///C:/WinAVR/doc/gcc/HTML/gcc-4.3.2/gcc/Code-Gen-Options.html

а также

file:///C:/WinAVR/doc/avr-libc/avr-libc-user-manual/index.html

так он ещё бы трафик пользователю сэкономил.

___________________________
— А я так XP-шку до конца и не прошёл...
— Так это же не игрушка, а ОС
— Откуда инфа 8-O ???


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 25 2011, 08:40
Сообщение #38


Местный
***

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



Спасибо за ответы !

Опять я возвращаюсь к своим любимым регистровым глобальным переменным.
Вначале программы обычно происходит инициализация переменных. В моей программе три регистровых глобальных переменных. Одна из них обьявленна как битовая область, и с ней проблем нет. Две других как беззнаковый байт (см. программу). В месте задания им начальных значений, компилятор игнорировал эти операции, чтобы я не делал. Все уровни оптимизации , кроме -O0 исключали эти команды. Но, после перемещения блока инициализации в отдельную подпрограмму , компилятор всеже их заметил, и правильно откомпилировал! У меня возникла мысль, что какието ключи не позволяют оптимизатору игнорировать команды в подпрограммах.
Хотел бы услышать ваши предположения.

Код
#include <avr/io.h>
#include <avr/interrupt.h>  // задает макросы sei() , cli()
#include <inttypes.h>

//=====================================================================
// определение регистров:
volatile register uint8_t FLCnt asm("r16"); //фоновый счетчик длительности переключения свдиода
volatile register uint8_t DBKCnt asm("r18"); //фоновый счетчик для отсчета периода блокировки опроса кнопок
volatile register struct
{
  uint8_t bDbRKey : 1;
  uint8_t bFLed : 1;
} RFGP asm ("r17");

//;----------------------------------------------------------------------------------------------------------------------------------------
//=== Определение макросов
#define sbi(p,b) (p |= (1<<b)) //Установить бит
//;----------------------------------------------------------------------------------------------------------------------------------------
//Определение портов:
/* направление для порта В*/
#define DIRB 0b00010001
/* Pull-ups для порта В*/
#define PUPB 0b00000101

//;----------------------------------------------------------------------------------------------------------------------------------------
//Определение контактов
#define Control1 PB4 /* линия управления VT (1 - откр; 0 - закр ) */
#define Btn1 PB2 /* линия кнопки (на общ.пров) */
#define Led PB0 /* линия светодиода ("1" - вкл. ч/з резистор на общ.) */

//;----------------------------------------------------------------------------------------------------------------------------------------
/* длительность запрета на опрос клавиш t=(101-1)*0,1=10 sec */
#define Vl_DBKCnt 101

/* t=5*0,1=0,5 sec */
#define Vl_FLCnt 5

// Маска кнопок:"Btn"
#define  KeyMask (1<<Btn1)|(1<<1)


//=====================================================================
//=====================================================================
SIGNAL ( SIG_OUTPUT_COMPARE0A)
{//______ Моргание светодиода t=5*0,1=0,5 sec
if (!(--FLCnt))
{//__ Переключение свдиода
  FLCnt=Vl_FLCnt;// перезагрузка ф.счетчика              !!!!
  ~(RFGP.bFLed);
  sbi (PINB,Led);// ________ Переключение свдиода !
}

//______ Формирование запрета на опрос клавиш t=(101-1)*0,1=10 sec
if (RFGP.bDbRKey==1)
{ //__ проверка на первый запуск
   if (DBKCnt == 0 )
    DBKCnt=Vl_DBKCnt;
   --DBKCnt;//__ продолжение счета
   if (DBKCnt==0) // checking of =0
   { //__ сброс флага
     RFGP.bDbRKey=0;
     DBKCnt=Vl_DBKCnt;
   }
}
}

//=============================================================================
//=============================================================================
int main (void)
{
//_________________________ ИНИЦИАЛИЗАЦИЯ _____________________________
uint8_t temp;

PORTB=PUPB; //иницализация порта B
DDRB=DIRB; // задание направления для порта B
TIMSK0=(1<<OCIE0A); /* установка разр. прер-ия по совпадению т/сч.0 с регистром OCR0A */
OCR0A=234; //загрузка регистра совпадения OCR0A коэф. деления
TCCR0A= (1<<WGM01); //установка режима СТС - обнуление Т/С0 при совпадении с регистром OCR0A
TCCR0B=(1<<CS02)|(1<<CS00); // <---- конфигурация и запуск сч-ка в реж. СТС с предделителем ckl/1024
RFGP.bDbRKey=0;
RFGP.bFLed=0;
[color="#ff0000"]DBKCnt=Vl_DBKCnt; //задание начальных значений для счетчиков
FLCnt=(uint8_t)Vl_FLCnt;[/color]

sei (); // Разрешение общего прерывания
//____________________ ЦИКЛ РАБОЧЕЙ ПРОГРАММЫ ______________________
while (1)
{ //____ Считывание кнопки
  temp=~(PINB);
  temp &= KeyMask;
  if (temp)
  {  //______ Обработка нажатия кн."Btn"
   if ( RFGP.bDbRKey==0)//____ проверка на запрет считывания кнопок
   { RFGP.bDbRKey=1; // sbr RFGP,(1<<bDbRKey)
     sbi (PINB,Control1); // ________ Переключение линии Control1 _______________!!!!!
   }
  }
}
}


Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Nov 25 2011, 09:27
Сообщение #39


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (MaxiMuz @ Nov 25 2011, 11:40) *
Хотел бы услышать ваши предположения.
Прочитайте еще раз про яйцо и микроволновку. Мне лень считать, сколько раз вам писали, что регистровую переменную нельзя делать volatile, о чем прямым текстом пишут создатели компилятора. Вы же с упорством пьяного продолжаете писать register volatile и пенять на компилятор.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 25 2011, 12:07
Сообщение #40


Местный
***

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



Цитата(Сергей Борщ @ Nov 25 2011, 12:27) *
Прочитайте еще раз про яйцо и микроволновку. Мне лень считать, сколько раз вам писали, что регистровую переменную нельзя делать volatile, о чем прямым текстом пишут создатели компилятора. Вы же с упорством пьяного продолжаете писать register volatile и пенять на компилятор.

Извиняюсь что возмутил вас употребением и применением volatile !
Кстати сказать, из ответ на вопрос о использовании Volatile к регистровым глобальным переменным я со своим плохим знанием английского понял что компилятор уже считает регистровые переменные как volatile. Другими словами использование квалификатора бессмысленно.
Я убрал в обьявлении переменных FLCnt, DBKCnt volatile, результат тотже !
Вопрос остается открытым
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 25 2011, 14:16
Сообщение #41


фанат дивана
******

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



Цитата(MaxiMuz @ Nov 25 2011, 18:07) *
Вопрос остается открытым

Какой?


--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 25 2011, 14:35
Сообщение #42


Нечётный пользователь.
******

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



Цитата(AHTOXA @ Nov 25 2011, 16:16) *
Какой?

Почему регистровые переменную, вне зависимости от наличя слова volatile, компилятор, предупредивший о своём отношении к таким объявлениям, не рассматривает как volatile и выкидывает из main() их инициализацию, так как в этой же main() к переменным больше обращений нет, а про обращение к ним из прерываний компилятор «не знает».


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
AHTOXA
сообщение Nov 25 2011, 19:17
Сообщение #43


фанат дивана
******

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



По-моему, на этот вопрос тоже уже ответили, и не раз sm.gif
Я на всякий случай ещё раз повторю ответ: да, в этом моменте компилятор работает криво.
Варианты решения проблемы тоже вроде все предложены:
  1. Не использовать регистровые переменные.
  2. Использовать, но не в качестве volatile-переменных.
  3. Использовать, но для обращения к этим переменным применять подпрограммы на (инлайн-)ассемблере.



--------------------
Если бы я знал, что такое электричество...
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 25 2011, 20:32
Сообщение #44


Нечётный пользователь.
******

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



Провёл маленький эксперимент.
Убрал все эти register... asm()
Начало файла стало выглядеть так:

Код
//=====================================================================
// определение регистров:
volatile uint8_t FLCnt;
volatile uint8_t DBKCnt;

#define DbRKey 0x01
#define FLed   0x02


Обработчик прерывания так:
Код
SIGNAL(SIG_OUTPUT_COMPARE0A)
{        
    uint8_t temp;

    temp = FLCnt;
    if (!(--temp)) {
        temp = Vl_FLCnt;
        //    ~(RFGP.bFLed);  Эта штука ничего осмысленного не делает.
        //    и в выходном коде от неё ничего И НЕ БЫЛО
        PINB |= _BV(Led);
    }
    FLCnt = temp;

    if ( GPIOR0 & DbRKey ) {
        temp = DBKCnt;
        // на мой взгляд странные манипуляции, но оставил как есть
        if (temp == 0)
            temp = Vl_DBKCnt;
        --temp;        
        if (temp == 0){    
            GPIOR0 &= ~DbRKey;
            temp = Vl_DBKCnt;
        }
        DBKCnt = temp;
        }
}

При компиляции для atmega168 количество команд в обработчиках прерывания для старого и нового варианта кода сохранилось.
Все push/pop в начале и в конце обработчика совпадают, общий ход практически тот же. Просто несколько команд mov заменилось на lds, sts.
В итоге длина в байтах для нового варианта увеличилась на 8 байт и стала 66 байт.
Время выполнения увеличилось на 4 такта.
Только время тут «абсолютно», а вот освобождение трёх зафиксированных до этого регистров освободит руки компилятору в других местах и общая длина кода всей программы ещё и уменьшиться может.

За что боролись?

Думаю, сначала нужно научиться просто на С писать, а потом про все эти зафиксированные регистры думать.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Nov 28 2011, 10:59
Сообщение #45


Местный
***

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



AHTOXA с вами не поспоришь sm.gif

ReAl По сути , кусок из вашего варианта :
Код
   temp = FLCnt;
    if (!(--temp)) {

подобен коду сформированному с использованием регистровых переменных:
Код
         if (!(--FLCnt))
  2e: 80 2f        mov r24, r16
  30: 81 50        subi r24, 0x01; 1
  32: 08 2f        mov r16, r24
  34: 11 f4        brne .+4

Но даже если закрыть глаза на бессмысленные mov rd,rs , как вы сами признали чуть быстрее и меньше по коду. И в использование возможностей железа по максимуму, даже учитывая корявость компилятора, нет ничего предосудительного sm.gif А абстрагирование от железа приводит к появлению таких опусов как Win7 ! с неоправданно раздутым кодом и тормозным ядром !
А если используется мощн.математический аппарат, то как я себе это представляю, здесь полезно оценить что важнее, быстый доступ к регистровым переменным или быстрое выполнение мат.операций.
Код
if ( GPIOR0 & DbRKey )
кстати в ATtiny13 (под него я пишу код) нет таких регистров вв./выв. которые можно так использовать!

Цитата(ReAl @ Nov 25 2011, 23:32) *
..........................
Думаю, сначала нужно научиться просто на С писать, а потом про все эти зафиксированные регистры думать.

с вами полностью согласен , но гибкое использование железа тоже часть "знания Си"

Сообщение отредактировал MaxiMuz - Nov 28 2011, 10:56
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 28 2011, 14:16
Сообщение #46


Нечётный пользователь.
******

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



Цитата(MaxiMuz @ Nov 28 2011, 12:59) *
подобен коду сформированному с использованием регистровых переменных:
Код
         if (!(--FLCnt))
  2e: 80 2f        mov r24, r16
  30: 81 50        subi r24, 0x01; 1
  32: 08 2f        mov r16, r24
  34: 11 f4        brne .+4

Но даже если закрыть глаза на бессмысленные mov rd,rs , как вы сами признали чуть быстрее и меньше по коду.
Но всё равно проиграет чисто-асмовой реализации гораздо больше, чем выиграет у «универсальной» реализации («универсальной» в том смысле, что точно так же можно написать для IAR/MSP430 и оно тоже будет оптимально в плане работы с volatile-переменными в памяти).

Цитата(MaxiMuz @ Nov 28 2011, 12:59) *
И в использование возможностей железа по максимуму, даже учитывая корявость компилятора, нет ничего предосудительного sm.gif А абстрагирование от железа приводит к появлению таких опусов как Win7 ! с неоправданно раздутым кодом и тормозным ядром!
А абстрагирование от языка и компилятора к чему приводит?
Сначала нужно навчиться по-максимуму использовать платформенно-независимые возможности языка, а то получается «вперёд к коммунизму минуя феодализм». А уже потом использовать учиться использовать возможности специфического компилятора для доступа к специфическим возможностям железа.
Если ставить телегу впереди лошади, то выходит как у Вас — оно-то вроде и короче, но для того, чтобы оно заработало правильно, приходится делать костыли в виде отдельно вызываемой функции инициализации этих переменных (rcall+ret сожрали 4 байта из выигрыша варианта без принудительно-регистровых переменных). А там, глядишь, и в других местах для нормального обращения к этим переменным придётся городить функции.

Цитата(MaxiMuz @ Nov 28 2011, 12:59) *
Код
if ( GPIOR0 & DbRKey )
кстати в ATtiny13 (под него я пишу код) нет таких регистров вв./выв. которые можно так использовать! с вами полностью согласен , но гибкое использование железа тоже часть "знания Си"
Нет. Это часть знания аппаратуры, а не языка. Эти же GPIOR можно и из ассемблера использовать, и из бейсика и что там ещё для AVR найдётся.
В теме до сих пор упоминался только ATtiny2313, у которого их три, вот я как-то и отнёс всё остальное к нему.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2011, 19:40
Сообщение #47


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



перед main воткните __attribute__ ((noreturn));
http://www.emerson.emory.edu/services/gcc/...Attributes.html
экономит "пару" байт


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
ReAl
сообщение Nov 28 2011, 20:17
Сообщение #48


Нечётный пользователь.
******

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



Для этого в AVR-GCC уже давно есть OS_main и OS_task, они что-то там глубже копают.
Если main() сама по себе довольно большая, то OS_main даст больше эффекта, чем noreturn.
...
Начиная с 4.2.2, если верить мне самому в исходниках порта scmRTOS :-)
Код
#if GCC_VERSION >= 40202
#define OS_PROCESS              __attribute__((OS_task))
#else
#define OS_PROCESS              __attribute__((__noreturn__))
#endif


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Nov 28 2011, 22:10
Сообщение #49


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



ну или так, да.
а ещё я из исходников библиотеки какие-то инициализации выкидывал, когда тини13а на сях программировал. тоже давало неслабый эффект.


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
ILYAUL
сообщение Nov 29 2011, 04:15
Сообщение #50


Профессионал
*****

Группа: Свой
Сообщений: 1 940
Регистрация: 16-12-07
Из: Москва
Пользователь №: 33 339



Цитата(sigmaN @ Nov 29 2011, 02:10) *
ну или так, да.
а ещё я из исходников библиотеки какие-то инициализации выкидывал, когда тини13а на сях программировал. тоже давало неслабый эффект.

ИМХО . Для 13 писать на С , можно только в рамках изучения С , там и asm сложно "развернуться", если задействовать все ее ресурсы.


--------------------
Закон Мерфи:

Чем тщательнее составлен проект, тем больше неразбериха, если что-то пошло не так
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Jan 23 2012, 09:15
Сообщение #51


Местный
***

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



Цитата(sigmaN @ Nov 28 2011, 22:40) *
перед main воткните __attribute__ ((noreturn));
http://www.emerson.emory.edu/services/gcc/...Attributes.html
экономит "пару" байт

Никакого действия этот предписание на программу не оказало, и я не понял из описания на что оно конкретно делает.
Go to the top of the page
 
+Quote Post
ARV
сообщение Jan 23 2012, 09:53
Сообщение #52


Профессионал
*****

Группа: Свой
Сообщений: 1 143
Регистрация: 30-09-08
Из: Новочеркасск
Пользователь №: 40 581



Цитата(ILYAUL @ Nov 29 2011, 08:15) *
ИМХО . Для 13 писать на С , можно только в рамках изучения С , там и asm сложно "развернуться", если задействовать все ее ресурсы.
не согласен. во-первых, все ресурсы МК вообще сложно задействовать одновременно (в одном проекте то есть), даже если МК "просторнее" тини13. а во-вторых, я лично последние годы пишу только на Си, причем для тини13 сделал несколько разных проектов, часто даже не напрягаясь с оптимизацией. последний проект - RGB-светильник с дистанционным управлением (пульт ДУ тоже на тини13) sm.gif на Си пишется достаточно комфортно.


--------------------
Я бы взял частями... но мне надо сразу.
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Jan 23 2012, 14:50
Сообщение #53


Местный
***

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



При использовании int OS_main (void) компилятор выдает: warning: no return statement in function returning non-void и до hex-файла дело не доходит. Ткните пальцем где можно об этом подробнее прочитать.
Go to the top of the page
 
+Quote Post
sigmaN
сообщение Jan 24 2012, 02:07
Сообщение #54


I WANT TO BELIEVE
******

Группа: Свой
Сообщений: 2 617
Регистрация: 9-03-08
Пользователь №: 35 751



warning это не error и по идее не должен приводить к трудностям с hex файлом.
no return statement in function returning non-void подсказывает вам, что функцию вы объявили как возвращающую значение(т.е. не void) а return в теле функции не встречается.
Самое простое: добавить в функцию return 0;


--------------------
The truth is out there...
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Feb 2 2012, 11:49
Сообщение #55


Местный
***

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



Цитата(sigmaN @ Jan 24 2012, 05:07) *
warning это не error и по идее не должен приводить к трудностям с hex файлом.
no return statement in function returning non-void подсказывает вам, что функцию вы объявили как возвращающую значение(т.е. не void) а return в теле функции не встречается.
Самое простое: добавить в функцию return 0;

добавил в конец функции int OS_main (void) оператор return 0;
предупреждение пропало, но ошибка линковщика , которую я в начале не заметил осталась :
Код
inking: copy_reg_struct.elf
avr-gcc -mmcu=attiny13a -I. -gdwarf-2 -DF_CPU=8000000UL -Os -funsigned-char -funsigned-bitfields -fpack-struct -fshort-enums -Wall -Wstrict-prototypes -Wa,-adhlns=copy_reg_struct.o  -std=gnu99 -MMD -MP -MF .dep/copy_reg_struct.elf.d copy_reg_struct.o --output copy_reg_struct.elf -Wl,-Map=copy_reg_struct.map,--cref,-gc-sections     -lm
c:/program files/winavr-20100110/bin/../lib/gcc/avr/4.3.3/../../../../avr/lib/avr25/crttn13a.o:(.init9+0x0): undefined reference to `main'
make.exe: *** [copy_reg_struct.elf] Error 1
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Feb 2 2012, 12:16
Сообщение #56


;
******

Группа: Участник
Сообщений: 5 646
Регистрация: 1-08-07
Пользователь №: 29 509



Таварисч не панимаит.
Код
int main(void) __attribute__((OS_main))
{
// blabla
  return 0;
}
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Feb 3 2012, 10:42
Сообщение #57


Местный
***

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



Цитата(_Pasha @ Feb 2 2012, 15:16) *
Таварисч не панимаит.
Код
int main(void) __attribute__((OS_main))
{
// blabla
  return 0;
}

Да! я не поимаю! в этом случае компил. кажет:
Код
copy_reg_struct.c:112: error: expected ',' or ';' before '{' token
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Feb 3 2012, 11:08
Сообщение #58


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



QUOTE (MaxiMuz @ Feb 3 2012, 12:42) *
Да! я не поимаю!
_Pasha описАлся.
CODE
__attribute__((OS_main))
int main(void)
{
// blabla
  return 0;
}


или
CODE
int main(void)  __attribute__((OS_main));

int main(void)
{
// blabla
  return 0;
}
И не спрашивайте "почему?". Так есть.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Oct 16 2012, 18:35
Сообщение #59


Местный
***

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



Доброго времяни суток!
Не стал создавать отдельной темы. Хочу прояснить для себя такой момент, фрагмент:
Код
#define  Mask (0x07)
int main (void)
{
uint8_t Cnt=0;
while (1)
    {
    if (Cnt &((unsigned char) Mask))
        {Buf1=1;
        }
        else
        { Buf1=2;
        }
        Cnt++;
    }
}
Где условие компилируется в:
Код
    if (Cnt &((unsigned char) Mask))
  56:    82 2f           mov    r24, r18
  58:    90 e0           ldi    r25, 0x00; 0
  5a:    87 70           andi    r24, 0x07; 7
  5c:    90 70           andi    r25, 0x00; 0
  5e:    89 2b           or    r24, r25
  60:    19 f0           breq    .+6     ; 0x68 <main+0x1c>

здесь игнорирование (unsigned char) перед Mask это особенности GCC компилятора ?
Т.к. AVR 8ми битный, можно ли отключить както 16битное расширение ?

Сообщение отредактировал MaxiMuz - Oct 16 2012, 18:37
Go to the top of the page
 
+Quote Post
Genadi Zawidowsk...
сообщение Oct 16 2012, 19:26
Сообщение #60


Профессионал
*****

Группа: Участник
Сообщений: 1 620
Регистрация: 22-06-07
Из: Санкт-Петербург, Россия
Пользователь №: 28 634



Используйте компилятор поновее (avr-gcc 4.7.2, avr-gcc 4.8) - будет Вам счастье (на моих проектах объём кода на 30% уменьшился):

Код
0000007c <main>:
  7c:    80 e0           ldi    r24, 0x00; 0
  7e:    92 e0           ldi    r25, 0x02; 2
  80:    21 e0           ldi    r18, 0x01; 1
  82:    37 e0           ldi    r19, 0x07; 7
  84:    38 23           and    r19, r24
  86:    19 f0           breq    .+6; 0x8e <main+0x12>
  88:    20 93 60 00     sts    0x0060, r18
  8c:    02 c0           rjmp    .+4; 0x92 <main+0x16>
  8e:    90 93 60 00     sts    0x0060, r25
  92:    8f 5f           subi    r24, 0xFF; 255
  94:    f6 cf           rjmp    .-20; 0x82 <main+0x6>


Берётся тут и подключается в AvrStudio 4.19 без проблем.

Сообщение отредактировал Genadi Zawidowski - Oct 16 2012, 19:41
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 17 2012, 06:15
Сообщение #61


Гуру
******

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



Цитата(MaxiMuz @ Oct 16 2012, 22:35) *
здесь игнорирование (unsigned char) перед Mask это особенности GCC компилятора ?

Это - не "игнорирование", а "integer promotion" прописанное в стандарте ISO/IEC 9899:1999
Go to the top of the page
 
+Quote Post
MaxiMuz
сообщение Oct 17 2012, 12:11
Сообщение #62


Местный
***

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



Цитата(Палыч @ Oct 17 2012, 09:15) *
Это - не "игнорирование", а "integer promotion" прописанное в стандарте ISO/IEC 9899:1999

т.е. этому стандарту не важно что в выражении стоит операция приведение типов ?
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Oct 17 2012, 12:59
Сообщение #63


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



В этом стандарте операция "&" выполняется над операндами не ниже (unsigned) int. Все, что меньшего размера приводится к этим типам. После вашего явного приведения к unsigned char. Затем оптимизатор может выкинуть не влияющие на результат операции, такие как сравнение заведомо нулевых старших байтов. Ваш компилятор действует строго по стандарту, но его оптимизатор недостаточно проработан - обновите компилятор.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
Go to the top of the page
 
+Quote Post
Палыч
сообщение Oct 17 2012, 13:04
Сообщение #64


Гуру
******

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



Цитата(MaxiMuz @ Oct 17 2012, 16:11) *
стандарту не важно что в выражении стоит операция приведение типов ?
Почему одна операция (в данном случае - приведение типов) должна быть "важнее" других операций (например, & или + или др.) ? Транслятор генерирует код в соответствии с написаной Вами программой на языке С и положениями стандарта. В п.5.1.2.3 "Program execution" стандарта в абзаце 10 приведен пример, иллюстрирующий Ваш случай:
Цитата
EXAMPLE 2 In executing the fragment
char c1, c2;
/* ... */
c1 = c1 + c2;
the ‘‘integer promotions’’ require that the abstract machine promote the value of each variable to int size
and then add the two ints and truncate the sum.
Go to the top of the page
 
+Quote Post

5 страниц V   1 2 3 > » 
Reply to this topicStart new topic
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0

 


RSS Текстовая версия Сейчас: 13th August 2025 - 04:10
Рейтинг@Mail.ru


Страница сгенерированна за 0.02338 секунд с 7
ELECTRONIX ©2004-2016