luben111 0 27 октября, 2009 Опубликовано 27 октября, 2009 (изменено) · Жалоба Не тайна что через использование ключевое слово register можно указать компилятору поставит переменную в регистр. В проекте можно тоже указать компилятору не использовать определенные регистры и потом создать глобальные регистровые переменные. Вопрос идет об локальных переменных в какой то процедуре - если в процедуре много переменных оптимизация часто не принимает во внимание мои инструкции поставит переменные в регистры. Например: register uint8_t var1, var2, var3, var4; // переменные в регистры var1 = 15; // установка значения var2 = 61; var3 = 45; var4 = 1; DDRA = var1; PORTC = var2; DDRA = var3; DDRB = var4; После компиляции часто можно увидеть что в листинге находиться что то вроде: // DDRA = var1; 0000017A E07F LDI R23, 15 // load R23 with 15 0000017C B97D OUT 0x0D, R23 // out to DDRA вместо ожидаемого: // DDRA = var1; 0000017C B97D OUT 0x0D, R21 // out directly var1 to DDRA Как можно обмануть компилятору и поставить локальные переменные воистину в регистры (без использование глобальных переменных в регистров). Изменено 27 октября, 2009 пользователем Student2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Совершенно непонятно, почему Вы ожидаете от компилятора опустить инициализацию переменных (а больше отличий между реальным и желаемым листингом нет). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
luben111 0 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Конечно компилятор надо инициализировать переменные, но я говорю об что то совершенно другое - компилятор видит что переменная все время имеет одна и та же стойность и делает что то неладное - вместо чтобы загрузит регистр и хранит этот регистр только для этой переменной он использует один и тот регистр для все переменные var1..var4 - перед каждой установке PORTA, DDRA и т.д. он загружает константу в регистр и только потом загружает PORTA, DDRA. В итоге это одна инструкция больше! Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Гость MALLOY2 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба ключевое слово register Не указать, а рекомендовать, компилятор сам решает куда и как ее засунуть если есть возможность ее в регистре разместить он ее и сам разместит. В современных компиляторах абсолютно бесполезная директива осталась только для совместимости со стандартом. В итоге это одна инструкция больше! Какая риазница ? LDI R0, 15; // установка значения LDI R1, 61; LDI R2, 45; LDI R3, 1; OUT DDRA, R0; OUT PORTC, R1; OUT DDRA, R2; OUT DDRB, R3; или LDI R0, 15; OUT DDRA, R0; LDI R0, 61; OUT PORTC, R0; LDI R0, 45; OUT DDRA, R0; LDI R0, 1; OUT DDRB, R0; Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
luben111 0 27 октября, 2009 Опубликовано 27 октября, 2009 (изменено) · Жалоба Какая риазница ? Если установка PORTA DDRA произходить в цикле разница получается доволно большая и заметная. LDI R0, 15; // установка значения LDI R1, 61; LDI R2, 45; LDI R3, 1; .... for (uint16_t ii = 0; ii < 1000; ii++) { OUT DDRA, R0; OUT PORTC, R1; OUT DDRA, R2; OUT DDRB, R3; } намного быстрее (1000 clocks!!!!) чем : for (uint16_t ii = 0; ii < 1000; ii++) { LDI R0, 15; OUT DDRA, R0; LDI R0, 61; OUT PORTC, R0; LDI R0, 45; OUT DDRA, R0; LDI R0, 1; OUT DDRB, R0; } Изменено 27 октября, 2009 пользователем Student2 Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Посмотрел внимательнее. Судя по всему, компилятор - IAR. Действительно, иногда у него так бывает, жадность до регистров (т.е. не портить лишнего) пересиливает CSE. Я в таких случаях делаю код вот такого плана: static void fooxx_stage2(uint8_t var1, uint8_t var2, uint8_t var3, uint8_t var4); void fooxx(void) { fooxx_stage2(15,61,45,1); } static void fooxx_stage2(uint8_t var1, uint8_t var2, uint8_t var3, uint8_t var4) { for(uint16_t ii=0; ii<1000; ii++) { DDRD = var1; PORTC = var2; DDRD = var3; DDRB = var4; } } RSEG CODE:CODE:NOROOT(1) // 7 void fooxx(void) fooxx: // 8 { // 9 fooxx_stage2(15,61,45,1); LDI R19, 1 LDI R18, 45 LDI R17, 61 LDI R16, 15 REQUIRE fooxx_stage2 ; // Fall through to label fooxx_stage2 // 10 } // 11 RSEG CODE:CODE:NOROOT(1) // 12 static void fooxx_stage2(uint8_t var1, uint8_t var2, uint8_t var3, uint8_t var4) fooxx_stage2: // 13 { MOVW R21:R20, R25:R24 // 14 for(uint16_t ii=0; ii<1000; ii++) LDI R24, 232 LDI R25, 3 // 15 { // 16 DDRD = var1; ??fooxx_stage2_0: OUT 0x0A, R16 // 17 PORTC = var2; OUT 0x08, R17 // 18 DDRD = var3; OUT 0x0A, R18 // 19 DDRB = var4; OUT 0x04, R19 // 20 } SBIW R25:R24, 1 BRNE ??fooxx_stage2_0 // 21 } MOVW R25:R24, R21:R20 RET Но лучше так делать только при сильной необходимости. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
luben111 0 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Спасибо - это точно что хотел узнать. Вопрос - а что будет если использовать #pragma inline=forced перед fooxx(). Мне все таки не хочется вызывать процедуру где можно и не вызывать (каждый CALL может сопровождаться громоздким сегментом сохранения - восстановления регистров). Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Вопрос - а что будет если использовать #pragma inline=forced перед fooxx(). Ничего хорошего. Вам просто надо сделать так - разбить Ваш код (который был в виде одной процедуры) на две части, первая из которых лежит в процедуре fooxx, например, подготавливая все исходные данные, а вторая - fooxx_stage2, где и происходят необходимые действия. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
_Pasha 0 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба Ничего хорошего. В гцц такие объявления: static inline void fooxx_stage2(const uint8_t var1, const uint8_t var2, const uint8_t var3, const uint8_t var4); не вызывают указанных проблем с оверхедом. Как по-иарски, не знаю... Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Rst7 5 27 октября, 2009 Опубликовано 27 октября, 2009 · Жалоба не вызывают указанных проблем с оверхедом. Как по-иарски, не знаю... Так оно и так инлайнится почти. Поглядите на листинг. А инлайнить stage2 - это тоже самое, что написать все вместе и получить унылый результат. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Bill 0 9 ноября, 2009 Опубликовано 9 ноября, 2009 · Жалоба Не тайна... Компилятор вообще игнорирует ключевое слово register. Если хорошенько подумаете, то поймете почему. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
sKWO 0 14 ноября, 2009 Опубликовано 14 ноября, 2009 · Жалоба Интерессно, а переменную типа флоат компилятор используя соглашения предлагает разместить поочерёдно в регистрах с 16- го по 19й при инициализ. ф-ции fooxx. В fooxx_stage2 при попытке доступа к регистрам они сначала размещаются на стеке а потом меняются местами тоесть обратно перегружаются в обратном порядке (19 равен 16му и тд). Почему компилятор поступает так с рабочими регистрами остаётся загадкой. Пробовал с максимальной оптимизацией по скорости. Если в цикле например увеличивать её значение (переменной) то порядок проинициализированных рабочих регистров в ф-ции fooxx в fooxx_stage2 не изменяется. Ето нужно учитывать при написании асм функций. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться
Bill 0 19 ноября, 2009 Опубликовано 19 ноября, 2009 · Жалоба Не тайна что через использование ключевое слово register можно указать компилятору поставит переменную в регистр. В проекте можно тоже указать компилятору не использовать определенные регистры и потом создать глобальные регистровые переменные. Вопрос идет об локальных переменных в какой то процедуре - если в процедуре много переменных оптимизация часто не принимает во внимание мои инструкции поставит переменные в регистры. Например: register uint8_t var1, var2, var3, var4; // переменные в регистры var1 = 15; // установка значения var2 = 61; var3 = 45; var4 = 1; DDRA = var1; PORTC = var2; DDRA = var3; DDRB = var4; После компиляции часто можно увидеть что в листинге находиться что то вроде: // DDRA = var1; 0000017A E07F LDI R23, 15 // load R23 with 15 0000017C B97D OUT 0x0D, R23 // out to DDRA вместо ожидаемого: // DDRA = var1; 0000017C B97D OUT 0x0D, R21 // out directly var1 to DDRA Как можно обмануть компилятору и поставить локальные переменные воистину в регистры (без использование глобальных переменных в регистров). Я думаю, обманывать тут никого не нужно. Если судить по приведенному фрагменту кода, то необходимости отводить регистры под однократно используемые константы абсолютно нет. И компилятор это учел. Если бы эти константы использовались не один раЗ, то компилятор возможно и разместил бы их регистрах, но... Тут все зависит от количества локальных переменных. Если их число велико, то всех их в регистрах не разместишь. Поэтому для подобных операций используются рабочие регистры. Цитата Поделиться сообщением Ссылка на сообщение Поделиться на другие сайты Поделиться