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

 
 
 
Reply to this topicStart new topic
> Локалные переменные в регистры
Student2
сообщение Oct 27 2009, 03:37
Сообщение #1


Частый гость
**

Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737



Не тайна что через использование ключевое слово 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


Как можно обмануть компилятору и поставить локальные переменные воистину в регистры (без использование глобальных переменных в регистров).

Сообщение отредактировал Student2 - Oct 27 2009, 03:38
Go to the top of the page
 
+Quote Post
Rst7
сообщение Oct 27 2009, 03:55
Сообщение #2


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Совершенно непонятно, почему Вы ожидаете от компилятора опустить инициализацию переменных (а больше отличий между реальным и желаемым листингом нет).


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Student2
сообщение Oct 27 2009, 05:09
Сообщение #3


Частый гость
**

Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737



Конечно компилятор надо инициализировать переменные, но я говорю об что то совершенно другое - компилятор видит что переменная все время имеет одна и та же стойность и делает что то неладное

- вместо чтобы загрузит регистр и хранит этот регистр только для этой переменной он использует один и тот регистр для все переменные var1..var4

- перед каждой установке PORTA, DDRA и т.д. он загружает константу в регистр и только потом загружает PORTA, DDRA. В итоге это одна инструкция больше!
Go to the top of the page
 
+Quote Post
MALLOY2
сообщение Oct 27 2009, 05:34
Сообщение #4


Знающий
****

Группа: Validating
Сообщений: 838
Регистрация: 31-01-05
Пользователь №: 2 317



Цитата
ключевое слово 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;
Go to the top of the page
 
+Quote Post
Student2
сообщение Oct 27 2009, 05:59
Сообщение #5


Частый гость
**

Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737



Цитата
Какая риазница ?


Если установка 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;
}


Сообщение отредактировал Student2 - Oct 27 2009, 06:00
Go to the top of the page
 
+Quote Post
Rst7
сообщение Oct 27 2009, 06:39
Сообщение #6


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Посмотрел внимательнее. Судя по всему, компилятор - 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;
  }
}

CODE

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


Но лучше так делать только при сильной необходимости.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Student2
сообщение Oct 27 2009, 12:56
Сообщение #7


Частый гость
**

Группа: Участник
Сообщений: 83
Регистрация: 4-08-09
Из: Болгария / София
Пользователь №: 51 737



Спасибо - это точно что хотел узнать.

Вопрос - а что будет если использовать #pragma inline=forced перед fooxx(). Мне все таки не хочется вызывать процедуру где можно и не вызывать (каждый CALL может сопровождаться громоздким сегментом сохранения - восстановления регистров).
Go to the top of the page
 
+Quote Post
Rst7
сообщение Oct 27 2009, 13:05
Сообщение #8


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
Вопрос - а что будет если использовать #pragma inline=forced перед fooxx().


Ничего хорошего. Вам просто надо сделать так - разбить Ваш код (который был в виде одной процедуры) на две части, первая из которых лежит в процедуре fooxx, например, подготавливая все исходные данные, а вторая - fooxx_stage2, где и происходят необходимые действия.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
_Pasha
сообщение Oct 27 2009, 13:41
Сообщение #9


;
******

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



Цитата(Rst7 @ Oct 27 2009, 17:05) *
Ничего хорошего.

В гцц такие объявления:
Код
static inline void fooxx_stage2(const uint8_t var1, const uint8_t var2, const  uint8_t var3, const uint8_t var4);

не вызывают указанных проблем с оверхедом. Как по-иарски, не знаю...
Go to the top of the page
 
+Quote Post
Rst7
сообщение Oct 27 2009, 13:49
Сообщение #10


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



Цитата
не вызывают указанных проблем с оверхедом. Как по-иарски, не знаю...


Так оно и так инлайнится почти. Поглядите на листинг. А инлайнить stage2 - это тоже самое, что написать все вместе и получить унылый результат.


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
_Bill
сообщение Nov 9 2009, 20:10
Сообщение #11


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(Student2 @ Oct 27 2009, 07:37) *
Не тайна...

Компилятор вообще игнорирует ключевое слово register. Если хорошенько подумаете, то поймете почему.
Причина редактирования: Бездумное цитирование
Go to the top of the page
 
+Quote Post
sKWO
сообщение Nov 14 2009, 10:23
Сообщение #12


Местный
***

Группа: Участник
Сообщений: 355
Регистрация: 27-03-07
Из: Україна, Чуднів
Пользователь №: 26 530



Интерессно, а переменную типа флоат компилятор используя соглашения предлагает разместить поочерёдно в регистрах с 16- го по 19й при инициализ. ф-ции fooxx.
В fooxx_stage2 при попытке доступа к регистрам они сначала размещаются на стеке а потом меняются местами тоесть обратно перегружаются в обратном порядке (19 равен 16му и тд).
Почему компилятор поступает так с рабочими регистрами остаётся загадкой. Пробовал с максимальной оптимизацией по скорости.
Если в цикле например увеличивать её значение (переменной) то порядок проинициализированных рабочих регистров в ф-ции fooxx в fooxx_stage2 не изменяется.
Ето нужно учитывать при написании асм функций.


--------------------
нельзя недооценивать предсказуемость глупости
Go to the top of the page
 
+Quote Post
_Bill
сообщение Nov 19 2009, 19:44
Сообщение #13


Местный
***

Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219



Цитата(Student2 @ Oct 27 2009, 07:37) *
Не тайна что через использование ключевое слово 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


Как можно обмануть компилятору и поставить локальные переменные воистину в регистры (без использование глобальных переменных в регистров).

Я думаю, обманывать тут никого не нужно. Если судить по приведенному фрагменту кода, то необходимости отводить регистры под однократно используемые константы абсолютно нет. И компилятор это учел. Если бы эти константы использовались не один раЗ, то компилятор возможно и разместил бы их регистрах, но... Тут все зависит от количества локальных переменных. Если их число велико, то всех их в регистрах не разместишь. Поэтому для подобных операций используются рабочие регистры.
Go to the top of the page
 
+Quote Post

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

 


RSS Текстовая версия Сейчас: 22nd July 2025 - 15:48
Рейтинг@Mail.ru


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