Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: WinAVR-20100110
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > GNU/OpenSource средства разработки
Страницы: 1, 2, 3
Genadi Zawidowski
Цитата(demiurg_spb @ Aug 10 2012, 11:24) *
Я её тоже находил, но и также находил инфу что с ней что-то не так, возможно уже пофиксили.
В ней binutils какой-то экспериментальный
Код
Binutils 2.22.52.20120702 (development snapshot)
и вот с ним что-то не совсем чисто.
Так что я бы её не советовал использовать в боевых условиях.


Эта сборка чуть похуже с объёмом FLASH обходится (на 32 кило - 300 байт проигрыша).
Она поновее (компилятор не пререлиз)...
Интересно, что не так... Вот у halfdoom проект не собрался в режиме совместимости - у меня собирался нормально...

Перевёл проект на использование __flash вместо pgm_read_xxx - в основном приводило к маленьким уменьшениям кода (на 4..10 байт на одну правку, если оптимизатор не мог использовать это. Если мог - до сотни байт). Иногда к увеличению на десяток байт. В основном уменьшает.
demiurg_spb
Не знаю... У меня все проекты собираются.
Вы эти флаги пробовали применять? С ними ещё злее оптимизирует, правда мало шансов, что с -flto соберётся...
Код
#CFLAGS += -flto
#CFLAGS += -mbranch-cost=
CFLAGS += -fno-tree-switch-conversion
CFLAGS += -mstrict-X
CFLAGS += -maccumulate-args

Genadi Zawidowski
Цитата
Не знаю... У меня все проекты собираются.


Так и уменя тоже - собираются. Это у halfdoom странная проблема - я к тому, что на developer release могли ругаться из-за каких то не тех проблем.
Genadi Zawidowski
Так, все-таки, кто знает, как можно получить предупреждение компилятора в таких местах:

Код
const __flash char * pcf1;
const char * pc2;

void test1(void)
{
    pcf1 = pc2;
}

void test2(void)
{
    pc2 = pcf1;
}
halfdoom
В общем, собрал четыре проекта: самый маленький ~2КБ, на нем выигрыш составил 1.2%, самый большой - 29КБ, выигрыш 4.7%. Остальные где-то посередине. Оптимизация, в основном, коснулась избыточных загрузок регистров, заметно лучше используются X+ команды, в терминальных функциях теперь задействуется Y регистр.
Genadi Zawidowski
Странно, мало.

Мой проект выложен в теме, в нём нет ассемблера вообще. Может, у Вас что-то мешает оптимизатору? У меня только ключ -Os.
demiurg_spb
Линкеру нужны ещё такие ключи как оказалось...
Цитата
-nodefaultlibs -lm -lgcc -lc

С ними правильные либы подключаются.
Да и кстати с lto у меня небольшие проекты (до 16К) собираются нормально.
Наконец-то lto полноценно заменил combine. А то блин я уже было отчаялся ждать этого радостного моментаsm.gif
Вот пример похвальной оптимизации:
CODE
//fifo.tx.cnt - волатильная переменная uint16_t;
//было:
if (!(--rs->fifo.tx.cnt))
624c: 80 91 15 06 lds r24, 0x0615
6250: 90 91 16 06 lds r25, 0x0616
6254: 01 97 sbiw r24, 0x01 ; 1
6256: 90 93 16 06 sts 0x0616, r25
625a: 80 93 15 06 sts 0x0615, r24
625e: 80 91 15 06 lds r24, 0x0615
6262: 90 91 16 06 lds r25, 0x0616
6266: 89 2b or r24, r25
6268: 29 f4 brne .+10 ; 0x6274

//стало:
if (!(--rs->fifo.tx.cnt))
613c: 80 91 15 06 lds r24, 0x0615
6140: 90 91 16 06 lds r25, 0x0616
6144: 01 97 sbiw r24, 0x01 ; 1
6146: 90 93 16 06 sts 0x0616, r25
614a: 80 93 15 06 sts 0x0615, r24
614e: 89 2b or r24, r25
6150: 29 f4 brne .+10 ; 0x615c
Genadi Zawidowski
Ну -nodefaultlibs немного не в тему...
А в результате (-flto -Os) теперь вместо 27 килобайт 26 стало... И это всё от изначального объёма 32 килобайта... Я тоже давно ждал этого!
(-flto -Os добавил в ключи линкера).
halfdoom
Цитата(Genadi Zawidowski @ Aug 13 2012, 16:13) *
Может, у Вас что-то мешает оптимизатору? У меня только ключ -Os.

Тоже Os, просто код написан в стиле "здесь оптимизатору делать нечего". Компилятору остается только грамотно разложить переменные по регистрам.
Genadi Zawidowski
Я как раз писал в стиле "оптимизируйте пожалуйста", но это оптимизировалось уже несколько последних лет одинаково.
Например, я проверял - нет смысла внутри выражения делать присваивания, что снижает читаемость - оптимизатор gcc это давным-давно реорганизовывал. Но -flto порадовало!
_Pasha
Цитата(demiurg_spb @ Aug 13 2012, 16:50) *
Вот пример похвальной оптимизации

Что-то такая трактовка volatile начинает напрягать. Они, получается, неявно сделали винегрет из атомарной операции преддекремента и принципиальных неатомарностей доступа к переменной. Получается, что преддекремент живет своей жизнью... правда, хорошо бы примерчик придумать, где это вредно, но фантазии пока не хватает. Наверное, пока ни у кого не хватило.
demiurg_spb
Цитата(Genadi Zawidowski @ Aug 13 2012, 18:25) *
Ну -nodefaultlibs немного не в тему...
Кому как... У меня без этого на одном из проектов было +2К в сравнении с WinAVR, и это с lto.


Цитата(_Pasha @ Aug 13 2012, 18:53) *
Что-то такая трактовка volatile начинает напрягать.
Ну не знаю... Я специально старался писать код так чтобы получить именно то, что наконец получилось. Ничего вредного пока в этом не усматриваю.
_Pasha
Цитата(demiurg_spb @ Aug 14 2012, 08:21) *
Ну не знаю... Я специально старался писать код так чтобы получить именно то, что наконец получилось. Ничего вредного пока в этом не усматриваю.

Вы имеете в виду одним выражением? Дык тут - никаких возражений, вопросы именно по поводу того что CSE(вспомнил, как оно называется), имеет более высокий приоритет, чем безусловная по определению отмена оптимизации у volatile. Оно-то симпатичнее выглядит, но, с виду, конфликтует со стандартами.
Полезши в гугль, нашел, откуда ножки. Вкратце - поскольку имеется сильная заточенность под х86, инкремент волатайла при работе CSE, происходит через косвенное обращение к памяти, и за одну команду, что load/store архитектурах невозможно. Где-то там и вычитал такой пример.
demiurg_spb
Цитата(_Pasha @ Aug 14 2012, 15:27) *
Вы имеете в виду одним выражением?
Да.
Цитата
Дык тут - никаких возражений, вопросы именно по поводу того что CSE(вспомнил, как оно называется), имеет более высокий приоритет, чем безусловная по определению отмена оптимизации у volatile. Оно-то симпатичнее выглядит, но, с виду, конфликтует со стандартами.
Да и шут с ним с конфликтом, главное чтобы программы работали так как от них ожидаешь. Или даже немного лучше:-)

Возвращаясь к avr-gcc-4.7.1...
Обнаружился один неприятный и один непонятный момент.
1) Все переменные в EEPROM секции располагаются в обратном порядке, т.е. было раньше x1 x2 x3, стало x3 x2 x1.
Такая фигня была уже как-то раз на одной из версий WinAVR её быстро тогда пофиксили.
2) При включении lto все неиспользуемые переменные из EEPROM выкидываются нафиг.

Мне пока видится только один выход: засунуть все EEPROM переменные в одну структуру.
AHTOXA
Цитата(demiurg_spb @ Aug 15 2012, 16:46) *
Мне пока видится только один выход: засунуть все EEPROM переменные в одну структуру.

Есть ещё
__attribute__((used))
Genadi Zawidowski
Цитата(demiurg_spb @ Aug 15 2012, 14:46) *
Мне пока видится только один выход: засунуть все EEPROM переменные в одну структуру.


А совместно с offsetof это решение позволит ещё и независящие от типа используемой памяти писать программы.
_Pasha
Цитата(demiurg_spb @ Aug 15 2012, 13:46) *
Мне пока видится только один выход: засунуть все EEPROM переменные в одну структуру.

Я никогда по другому и не делал sm.gif
В любой момент может возникнуть желание сделать резервный набор параметров.
AHTOXA
Цитата(Genadi Zawidowski @ Aug 15 2012, 17:06) *
А совместно с offsetof это решение позволит ещё и независящие от типа используемой памяти писать программы.

Это как? Методы чтения-то всё равно зависят от типа используемой памяти.
Genadi Zawidowski
Цитата(AHTOXA @ Aug 15 2012, 22:40) *
Это как? Методы чтения-то всё равно зависят от типа используемой памяти.


Именно. А пользоваться тем, что эта память ещё одно адресное пространство на атмеге - всё равно, надо перед обращениями дожидаться заверщения циклов записи, ранее (возможно) иницииорваных...
ReAl
Цитата(_Pasha @ Aug 13 2012, 17:53) *
Что-то такая трактовка volatile начинает напрягать.
...
правда, хорошо бы примерчик придумать, где это вредно, но фантазии пока не хватает.


С примерчиком нет проблем, хоть и, возможно, слегка натянутым. Нужно просто придумывать на периферии, а не в ОЗУ.
Пусть у нас есть регистр периферийного устройства (нет проблем описать его так, что компилятор как таковой не сможет его отличить от переменной в памяти).
Пусть младший бит всегда читается нулевым а запись единички в него запускает какую-то операцию. Специально так аппаратуру сделали под INC для запуска операции, остальные управляющие биты при этом не меняются (во времена PDP-11 такое встречалось).
Все нули в регистре тоже что-то означают (скажем, отсутствие ошибок).
Ну вот читаем оттуда все нули, инкрементиреуем, записываем назад с 1 в младшем бите.
Вместо того, чтобы опять зачитать регистр и увидеть, что там все нули -- всегда в этой опреации видим регистр ненулевым.

А по поводу напряга… Ой, вредные они все. Я бы тоже считал, что после записи в volatile его нужно перезачитать. Но…
Там, кажется, и в С++ что-то слегка менялось.
Боюсь, что это где-то вблизи того, что --i эквивалентно «присваивающему выражению» i = i - 1.
А оно имеет «значение правой части приведенное к типу левой части со снятыми cv-квалификаторами»
Близкая проблема
Код
volatile int va;
int a;
  a = va = 5; // надо ли перезачитывать va??? говорят, что таки не надо...
Petka
Цитата(ReAl @ Aug 16 2012, 16:48) *
С примерчиком нет проблем, хоть и, возможно, слегка натянутым. Нужно просто придумывать на периферии, а не в ОЗУ.
.....

В той оптимизации ТОЧНО всё нормально.
Цитата
6.5.3.1 Prefix increment and decrement operators
Constraints
The operand of the prefix increment or decrement operator shall have qualified or
unqualified real or pointer type and shall be a modifiable lvalue.
Semantics
The value of the operand of the prefix ++ operator is incremented. The result is the new
value of the operand after incrementation. The expression ++E is equivalent to (E+=1).
See the discussions of additive operators and compound assignment for information on
constraints, types, side effects, and conversions and the effects of operations on pointers.
The prefix -- operator is analogous to the prefix ++ operator, except that the value of the
operand is decremented.


Далее:
Цитата
6.5.16.2 Compound assignment
Constraints
For the operators += and -= only, either the left operand shall be a pointer to an object
type and the right shall have integer type, or the left operand shall have qualified or
unqualified arithmetic type and the right shall have arithmetic type.
For the other operators, each operand shall have arithmetic type consistent with those
allowed by the corresponding binary operator.
Semantics
A compound assignment of the form E1 op = E2 differs from the simple assignment
expression E1 = E1 op (E2)
only in that the lvalue E1 is evaluated only once.
ReAl
На мой взгляд, тут всё же играют свойства присваивающего выражения, а не compound assignment.

compound assignment играет тут:
Код
volatile unsigned char vc;
unsigned char ca[3];

void foo1() {  
        ++ca[vc]; // вот тут ca[vc] находится один раз
}

void foo2()
{
        ca[vc] = ca[vc] + 1; // а тут дважды
}
Petka
Цитата(ReAl @ Aug 16 2012, 18:55) *
На мой взгляд, тут всё же играют свойства присваивающего выражения, а не compound assignment.
....

Я про оптимизацию этого куска кода:
Код
if (!(--rs->fifo.tx.cnt))

В нем оптимизатор всё сделал правильно. Никаких "вольных" трактовок volatile.
ReAl
А я про то, что к этой правильности evaluated only once не имеет отношения :-)
Код
volatile unsigned char vc;
unsigned char v;

void foo1()
{
    if (++vc == 0) v = 0; // тут для vc работает evaluated only once
}

void foo2()
{
    if ( (vc = vc + 1) == 0) v = 0; // тут для vc НЕ работает evaluated only once
}
Функции foo1() и foo2() компилируются одинаково разными версиями компиляторов.
4.5.3 в обеих функциях делает дополнительное считывание vc для проверки на 0
4.7.0 в обеих функциях не делает дополнительное считывание vc для проверки на 0

evaluated only once имеет отношение к тому примеру, который привел я. С ним наоборот —
в foo1() определение адреса элемента массива для инкремента делается один раз обеими комипляторами
в foo2() определение адресов элементов массива делается два раза обеими компиляторами, один раз для считывания, один раз для записи (у 4.7.0 немного эффективнее код, но логика та же — два раза подряд зачитывается vc, вычисляется два адреса в X и Z, потом ld reg, X $ inc reg $ st Z, reg ).

К обсуждаемой оптимизации имеет отношение другое место, то ж самое, которое относится к
Код
volatile unsigned char vc;
unsigned char v;
    v = vc = 0; // Напрямую писать 0 в v , а не считывать vc
А именно:
Цитата(ISO/IEC 9899 @ Dec 01 1999)
6.5.16 Assignment operators

3 An assignment operator stores a value in the object designated by the left operand. An assignment expression has the value of the left operand after the assignment, but is not an lvalue. An assignment expression has the value of the left operand after the assignment, but is not an lvalue. The type of an assignment expression is the type of the left operand unless the left operand has qualified type, in which case it is the unqualified version of the type of the left operand.

Т.е. ++vc, равно как и vc = vc + 1 имеют значение vc + 1 но имеет тип просто unsigned char. И вообще — не является lvalue, не есть объектом, cуществующим где-то, кроме временных ячеек абстрактной машины.

p.s[0] т.е., выходит даже, что это багфикс, а не улучшение оптимизатора ???
Что предыдущие компиляторы ни в коем случае не должны были зачитывать, так как это не требуется стандартом (и фактически отвергается -- «is not an lvalue», результат выражения равен значению правой части, приведенной к неквалифицированному типу левой, существует только как результат, но не как объект), но может породить (неучитываемый и неизвестный) побочный эффект?

p.s[1] Сергей Борщ: я так и не прочёл толком те линки, которые тогда по быстрячку нагуглил и тебе в джаббер кинул laughing.gif . Но, кажется, они об этом biggrin.gif
_Pasha
Код
volatile a;
a=a;// а как жеж вот это
(void) a; // или это

?
ReAl
Цитата(_Pasha @ Aug 17 2012, 22:44) *
Код
volatile a;
a=a;// а как жеж вот это
(void) a; // или это

?

С a=a; всё нормально, один раз читается и один раз записывается. А для b = a = a; второй раз зачитывать a не нужно.

Со вторым хитрее, в C побочнй эффект от оценки выражения a; нужно выполнить, даже если само значение выражения нигде не используется.
В C++ вроде что-то с rvalue/lvalue похимичили и в таком месте зачитывание a вроде бы не обязательно. Не разобрался ещё.
Genadi Zawidowski
коллеги, так кто-нибудь знает, как заставить gcc 4.7.1 для AVR выдавать предуперждения в случае присваиваний вроде
Цитата
const char __flash * pcf;
const char * pc;

pcf = pc;
pc = pcf;

-Wall стоит, -Wextra не помогает.



_Pasha
Дыкть.. ошибка должна быть, т.к. const... rolleyes.gif
Genadi Zawidowski
Цитата(_Pasha @ Aug 25 2012, 13:43) *
Дыкть.. ошибка должна быть, т.к. const... rolleyes.gif


const и там и там. это разные адресные пространства.
_Pasha
Цитата(Genadi Zawidowski @ Aug 25 2012, 13:17) *
const и там и там. это разные адресные пространства.

Не знаю, что за путаница, но lvalue const это есть ошибка.
Genadi Zawidowski
Речь о присваивании указателей на константные объекты в разных арресных пространствах.
Сам указатель не константный.
Константный указатель на константный char выглядит так:
const char * const p;
Genadi Zawidowski
http://sourceforge.net/projects/mobileches...hots%20(Win32)/

появились
gcc 4.7.2
gcc 4.8.0

4.7.2 ещё компактнее, 4.8.0 в другую сторону.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.