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

 
 
> Компилятор в IAR, ньюансы обращения к переменным
king2
сообщение Nov 22 2006, 02:23
Сообщение #1


Местный
***

Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646



Снова не пойму как IAR работает с переменными...
Оптимизация вся выключена, дабы не влиять излишне.

Имеем такой вот код:

Код
    111                    tmpByte <<= 1;
   \   00000464   9100....           LDS     R16, tmpByte
   \   00000468   0F00               LSL     R16
   \   0000046A   9300....           STS     tmpByte, R16
    112                    tmpByte |= tmp_bit;
   \   0000046E   8108               LD      R16, Y
   \   00000470   ....               LDI     R30, LOW(tmpByte)
   \   00000472   ....               LDI     R31, (tmpByte) >> 8
   \   00000474   8110               LD      R17, Z
   \   00000476   2B10               OR      R17, R16
   \   00000478   8310               ST      Z, R17


Почему компилятор, имея в регистре значение переменной, и следующую операцию с ней же, тем не менее сначала сохраняет ее, а потом загружает? Переменная не volatile.
Почему в первом и втором случае обращение к одной и той же переменной делается по разному??
Как избежать такого извращенного обращения к переменным?

Эквивалентный (нормальный) код:
Код
    114                    tmpByte = (tmpByte<<1) | tmp_bit;
   \   0000047A   9100....           LDS     R16, tmpByte
   \   0000047E   0F00               LSL     R16
   \   00000480   8118               LD      R17, Y
   \   00000482   2B10               OR      R17, R16
   \   00000484   9310....           STS     tmpByte, R17


Спасибо заранее!
Go to the top of the page
 
+Quote Post
3 страниц V   1 2 3 >  
Start new topic
Ответов (1 - 44)
rezident
сообщение Nov 22 2006, 02:42
Сообщение #2


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



ИМХО потому что запись
Код
tmpByte <<= 1;

на самом деле краткая и обозначает
Код
tmpByte = tmpByte << 1;

Аналогично
Код
tmpByte |= tmp_bit;

обозначает
Код
tmpByte = tmpByte | tmp_bit;

Поскольку tmpByte является и источником-операндом и приемником результата, то компилятор вполне логично каждую команду раскладывает так, как ему предписано. А вот с включенной оптимизацией он возможно соптимизирует код к такому виду, который вы считаете нормальным.
Go to the top of the page
 
+Quote Post
king2
сообщение Nov 22 2006, 03:26
Сообщение #3


Местный
***

Группа: Свой
Сообщений: 255
Регистрация: 17-08-06
Из: Москва
Пользователь №: 19 646



А почему оно в одном случае загружает переменную из памяти при помощи LDS, а в другом через LDI?
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Nov 22 2006, 10:50
Сообщение #4


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(king2 @ Nov 22 2006, 02:26) *
А почему оно в одном случае загружает переменную из памяти при помощи LDS, а в другом через LDI?

И по обьёму кода и по скорости варианты lds/sts и ldi/ldi/ld/st эквивалентны.
Второй вариант начинает иметь преимущество если переменная длиннее одного байта или когда она участвует в цепочечных операциях.
Go to the top of the page
 
+Quote Post
dxp
сообщение Nov 22 2006, 11:57
Сообщение #5


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата
Цитата(king2 @ Nov 22 2006, 02:26) *

А почему оно в одном случае загружает переменную из памяти при помощи LDS, а в другом через LDI?

И по обьёму кода и по скорости варианты lds/sts и ldi/ldi/ld/st эквивалентны.

Почти эквивалентны. Первый вариант все ж чуток быстрее, насколько помню. Но по объему если работа с объектом больше одного байта, второй начинает неслабо рулить.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 7 2006, 23:06
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



На этот раз для меня не понятный момент. До этого - не встречался с такой ерундой.
Переменная объявлена так (начало файла)

int16_t static HeadInBuf=0, EndInBuf=0; // RS232. Указатели буфера. Указатель на голову и хвост достоверных данных

Внизу в колове имеется такой оператор.
...
while (HeadInBuf == EndInBuf)
AnswerGo(); // Ждать прихода символа с RS485
....

Сижу в отладчике - вижу, что переменные HeadInBuf и EndInBuf - разные (пришёл пакет данных), но условие не проверяется, непрерывно выполняется AnswerGo(). И из цикла не выходит.

Скорее всего надо чего-то указать компилятору при инициализации переменных. Вопрос - что?
Go to the top of the page
 
+Quote Post
rezident
сообщение Dec 8 2006, 01:01
Сообщение #7


Гуру
******

Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882



Цитата(SasaVitebsk @ Dec 8 2006, 01:06) *
Скорее всего надо чего-то указать компилятору при инициализации переменных. Вопрос - что?

Добавить volatile в объявлении переменных. Или даже заменить static на volatile, т.к. я не уверен, что компилятор съест их оба враз.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 8 2006, 02:52
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(rezident @ Dec 8 2006, 00:01) *
заменить static на volatile, т.к. я не уверен, что компилятор съест их оба враз.

Cовершенно разные ни коим образом не противоречащие друг-другу вещи - не может не скушать.
Правда следует отметить, что static ни каким боком к проблеме не относится.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 8 2006, 03:12
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Информация к размышлению. Объявление не менял. Поменял конструкцию на вот такую.

do
AnswerGo();
while (HeadInBuf == EndInBuf); // Ждать прихода символа с RS485

И всё заработало.

В обоих случаях смотрел откомпилированный текст.

В первом случае было типа

rcall ...
brne ...
rcall ...
rjmp PC-1 ( должно было компильнутся в PC-3)

Во втором случае придраться не к чему. Надо сказать что эта конструкция в тексте встречается 3 раза, и возможно он пытался к общему знаменателю придти. ???

Опции по оптимизации выставлены такие.
speed high
все птички
3 прохода
птичка
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 8 2006, 12:16
Сообщение #10


Местный
***

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



Цитата(SasaVitebsk @ Dec 8 2006, 03:12) *
Информация к размышлению. Объявление не менял. Поменял конструкцию на вот такую.

do
AnswerGo();
while (HeadInBuf == EndInBuf); // Ждать прихода символа с RS485

И всё заработало.

В обоих случаях смотрел откомпилированный текст.

В первом случае было типа

rcall ...
brne ...
rcall ...
rjmp PC-1 ( должно было компильнутся в PC-3)

Во втором случае придраться не к чему. Надо сказать что эта конструкция в тексте встречается 3 раза, и возможно он пытался к общему знаменателю придти. ???

Опции по оптимизации выставлены такие.
speed high
все птички
3 прохода
птичка

Все правильно. Вы должны были объявить переменные как volatile, в противном случае компилятор будет работать в цикле не с самими переменными, а с их копиями в регистрах. И первый вариант корректнее второго, ибо по смыслу требуется ответная реакция и ответ должен посылаться после получения запроса а не до него.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 8 2006, 13:24
Сообщение #11


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(_Bill @ Dec 8 2006, 12:16) *
Все правильно. Вы должны были объявить переменные как volatile, в противном случае компилятор будет работать в цикле не с самими переменными, а с их копиями в регистрах. И первый вариант корректнее второго, ибо по смыслу требуется ответная реакция и ответ должен посылаться после получения запроса а не до него.


Всем спасибо за ответы.
С точки зрения логики работы программы - оба варианта для меня равнозначны. Так как ответ выдаётся ч/з паузу после приёма предыдущего пакета, а выход из цикла - после получения нового. Сама конструкция несколько тяжеловесней, но не буду об этом.

Хочу спросить следующий вопрос. Таким образом после объявления переменной как volatile, код (в общем случае) должен быть эффективнее? Я это к тому, что наблюдаю как компилятор создаёт в ряде случаев локальные переменные и с ними работает, а не обращается напрямую. Вопрос не эффективности, а защиты данных.
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 8 2006, 17:31
Сообщение #12


Местный
***

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



Цитата(SasaVitebsk @ Dec 8 2006, 13:24) *
Всем спасибо за ответы.
С точки зрения логики работы программы - оба варианта для меня равнозначны. Так как ответ выдаётся ч/з паузу после приёма предыдущего пакета, а выход из цикла - после получения нового. Сама конструкция несколько тяжеловесней, но не буду об этом.

Хочу спросить следующий вопрос. Таким образом после объявления переменной как volatile, код (в общем случае) должен быть эффективнее? Я это к тому, что наблюдаю как компилятор создаёт в ряде случаев локальные переменные и с ними работает, а не обращается напрямую. Вопрос не эффективности, а защиты данных.

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

Сообщение отредактировал _Bill - Dec 8 2006, 17:33
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 11 2006, 21:34
Сообщение #13


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Спасибо, разъяснили доступно. Извините за наглость, но чтобы окончательно закрыть данный вопрос, - а существуют ли директивы компилятора позволяющие включать/отключать оптимизацию выборочно по тексту? У меня, к примеру, это первый случай возникновения такой ситуации и не хочется глобально отключать оптимизацию переменной по той или иной причине.

Заранее спасибо за ответ.
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 11 2006, 22:38
Сообщение #14


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(SasaVitebsk @ Dec 11 2006, 20:34) *
а существуют ли директивы компилятора позволяющие включать/отключать оптимизацию выборочно по тексту?

Естественно.
#pragma optimize=
Подробности естественно в документации на компилятор.
Но в Вашем конкретном случае это просто использование volatile - можете считать, что это "отключение оптимизации" для конкретной переменной.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 18 2006, 16:58
Сообщение #15


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Цитата(rezident @ Nov 22 2006, 02:42) *
ИМХО потому что запись
Код
tmpByte <<= 1;

на самом деле краткая и обозначает
Код
tmpByte = tmpByte << 1;


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


Интересно мыслите, однако! Как вам такой пример, я честно говоря до сих пор не понимаю отчего IAR 4.11a так себя ведет. Оптимизация включена на максимум, окромя "cross-call"
Код
UCHAR TimeOut;            // глобальная переменная

__interrupt void TimerInt()
{
    if(TimeOut) TimeOut--;
};

Все это компилится в ледующий код:
Код
     LDS     R16, TimeOut
     TST     R16
     BREQ    0x392
  
    LDI     R30,0x9F
    LDI     R31,0x02
    LD      R16,Z
    DEC     R16
    ST      Z,R16

Сохраниение и восстановление стека я опустил.
Что мы видим? Грузим переменную, проверяем ее, если условие выполняется, опять ее же грузим (ЗАЧЕМ?), причем засоряя адресные регистры, модифицируем и сохраняем. В результате имеем 3 лишних комманды + 4 для сохраниения-восстановления адресных регистров. Более чем в 2 раза, однако! Никак оптимальным такой код не назовешь. Что скажете..?
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 18 2006, 18:01
Сообщение #16


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Или вот еще, тоже шедевр. Блин, чем больше в дизассемблере лажу - тем больше расстраиваюсь!
Код
   ;p_Mask[0] = RxBuf[0];
    00011A   910C             LD      R16,X
    00011C   01FC             MOVW    R30,R24
    00011E   8300             ST      Z,R16

   ;p_Mask[1] = RxBuf[1];
    000120   01FD             MOVW    R30,R26
    000122   8101             LDD     R16,Z+1
    000124   01FC             MOVW    R30,R24
    000126   8301             STD     Z+1,R16

   ;p_Mask[2] = RxBuf[2];
    000128   01FD             MOVW    R30,R26
    00012A   8102             LDD     R16,Z+2
    00012C   01FC             MOVW    R30,R24
    00012E   8302             STD     Z+2,R16

   ;p_Mask[3] = RxBuf[3];
    000130   01FD             MOVW    R30,R26
    000132   8103             LDD     R16,Z+3
    000134   01FC             MOVW    R30,R24
    000136   8303             STD     Z+3,R16

Простое копирование двух массивов. Ну почему не задействовать пару свободных регистров указателей, скажем Х и Z? Нет, мы будем каждый раз грузить новые значения указателей в ОДНУ регистровую пару, теряя по 2 машинных цикла на каждой итерции. Вроде ж начало получилось хорошее, а дальше... Не понимаю!

То же самое, реализованное в цикле. Еще хуже:
Код
  ;for(i=0; i<4; i++) p_Mask[i] = RxBuf[i];
    000118   019C             MOVW    R18,R24
    00011A   018D             MOVW    R16,R26
    00011C   E044             LDI     R20,0x04

    00011E   01F8             MOVW    R30,R16
    000120   9151             LD      R21,Z+
    000122   018F             MOVW    R16,R30
    000124   01F9             MOVW    R30,R18
    000126   9351             ST      Z+,R21
    000128   019F             MOVW    R18,R30
    
    00012A   954A             DEC     R20
    
    00012C   F7C1             BRNE    0x11E

Лучший код генерит только ICC, но вот полчить его в работающем виде и без ограничений по времени/коду пока сложно...
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 18 2006, 23:36
Сообщение #17


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Тем не менее местами просто сказка и песня! smile.gif Нарадоваться не могу. А вариант, который Вы показываете более характерен для подпрограмм или прерываний. Ещё некоторые моменты меня беспокоят.
Например вход выход из прерывания при максимальной оптимизации по времени типа такого:

834 }
\ ??CrossCallReturnLabel_588:
\ 00000214 BE4F OUT 0x3F, R4
\ 00000216 .... RCALL ?Subroutine201
\ ??CrossCallReturnLabel_563:
\ 00000218 .... RCALL ?Subroutine206
\ ??CrossCallReturnLabel_579:
\ 0000021A .... RCALL ?Subroutine200
\ ??CrossCallReturnLabel_560:
\ 0000021C 9049 LD R4, Y+
\ 0000021E 9518 RETI

Где каждая п/п - восстановление группы регистров.

У меня в настоящий момент М2560. Занято от силы 30К! Зачем так делать??? На ASMе такое даже в страшном сне не приснилось бы.

Конечно не по Вашему вопросу, но конструкцию которую Вы приводите при большом размере пересылаемых данных лучше сделать так.

memcpy(AdrActiveKom[i],AdrActiveKom[i+1],x);

(В данном случае AdrActiveKom - это массив ссылок) Для данных например так:

memcpy(&Status.Day+AdrStatus,&SlaveBuf[1],5);

Я проверял. Получается значительно эффективнее по времени.
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 19 2006, 09:52
Сообщение #18


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(Perepic @ Dec 18 2006, 21:01) *
Или вот еще, тоже шедевр. Блин, чем больше в дизассемблере лажу - тем больше расстраиваюсь!
Код
  ;p_Mask[0] = RxBuf[0];
    00011A   910C             LD      R16,X
    00011C   01FC             MOVW    R30,R24

[...]

    000134   01FC             MOVW    R30,R24
    000136   8303             STD     Z+3,R16

Простое копирование двух массивов. Ну почему не задействовать пару свободных регистров указателей, скажем Х и Z? Нет, мы будем каждый раз грузить новые значения указателей в ОДНУ регистровую пару, теряя по 2 машинных цикла на каждой итерции. Вроде ж начало получилось хорошее, а дальше... Не понимаю!


Попробовал ради интереса. Получил другие результаты. Код:

Код
char buf1[16];
char buf2[16];

// --------------------------------------------------------------------------
void main(void)
{

    buf1[0] = buf2[0];
    buf1[1] = buf2[1];
    buf1[2] = buf2[2];
    buf1[3] = buf2[4];
}
// --------------------------------------------------------------------------



Результат:

Код
   buf1[0] = buf2[0];
....               LDI     R30, LOW(buf1)
....               LDI     R31, (buf1) >> 8
8900               LDD     R16, Z+16
8300               ST      Z, R16
   buf1[1] = buf2[1];
8901               LDD     R16, Z+17
8301               STD     Z+1, R16
   buf1[2] = buf2[2];
8902               LDD     R16, Z+18
8302               STD     Z+2, R16
   buf1[3] = buf2[3];
8903               LDD     R16, Z+19
8303               STD     Z+3, R16


Ага, но тут массивы объявлены в одном файле, компилятор их "кластеризовал" и обошелся эффективно одним указателем, благо размеры массивов это позволяют. Усложним компилятору задачу, объявив один из массивов внешним:

Код
char buf1[16];
extern char buf2[16];


Результат:

Код
   buf1[0] = buf2[0];
....               LDI     R26, LOW(buf1)
....               LDI     R27, (buf1) >> 8
....               LDI     R30, LOW(buf2)
....               LDI     R31, (buf2) >> 8
8100               LD      R16, Z
930D               ST      X+, R16
   buf1[1] = buf2[1];
8101               LDD     R16, Z+1
930D               ST      X+, R16
   buf1[2] = buf2[2];
8102               LDD     R16, Z+2
930C               ST      X, R16
9712               SBIW    R27:R26, 2
   buf1[3] = buf2[3];
8103               LDD     R16, Z+3
01FD               MOVW    R31:R30, R27:R26
8303               STD     Z+3, R16


Он не так печален, как вашем примере. Может все-таки с оптимизацией что-то не то?

Цитата(Perepic @ Dec 18 2006, 21:01) *
То же самое, реализованное в цикле. Еще хуже:
Код
;for(i=0; i<4; i++) p_Mask[i] = RxBuf[i];
    000118   019C             MOVW    R18,R24
    00011A   018D             MOVW    R16,R26

[...]    

    00012A   954A             DEC     R20
    
    00012C   F7C1             BRNE    0x11E

Лучший код генерит только ICC, но вот полчить его в работающем виде и без ограничений по времени/коду пока сложно...


Код:

Код
char buf1[16];
extern char buf2[16];

// --------------------------------------------------------------------------
void main(void)
{

    for(char i = 0; i < sizeof(buf1); i++)
    {
        buf1[i] = buf2[i];
    }
}
// --------------------------------------------------------------------------


Результат:

Код
void main(void)
        main:
{
019D               MOVW    R19:R18, R27:R26

    for(char i = 0; i < sizeof(buf1); i++)
....               LDI     R26, LOW(buf1)
....               LDI     R27, (buf1) >> 8
....               LDI     R30, LOW(buf2)
....               LDI     R31, (buf2) >> 8
E100               LDI     R16, 16
    {
        buf1[i] = buf2[i];
        ??main_0:
9111               LD      R17, Z+
931D               ST      X+, R17
    }
950A               DEC     R16
F7E1               BRNE    ??main_0
}
01D9               MOVW    R27:R26, R19:R18
9508               RET

Что может быть короче?

IAR, как уже неоднократно говорилось и доказывалось, является лучшим компилятором для AVR на сегодняшний день. На втором месте с небольшим отставанием прочно находится AVR-GCC. Никакие ICC по качеству кодогенерации с этими двумя соревноваться не могут.

Код, который вы показали, был характерен для IAR'овских компляторов версий 2.хх - они там упорно делали все подобные обращения в память через Z-pointer, что далеко не всегда хорошо, на что было указано и в версиях 3.хх уже ситуация изменилась к лучшему. Основная же причина сидит не в компиляторах, а в самом AVR, в котором мало (всего два) полноценных аппаратных регистра-указателя (Y и Z, X - неполноценный, у него отсутствует очень важный режим адресации со смещением). Т.е. один из указателей занят под указатель стека данных (еще один, мягко говоря, неудачный момент AVR - обо всех этих "фичах" AVR уже подробно говорилось, если интересно, поищите по форуму), остается один Z-pointer, который компилятор и пытается использовать. В данном случае удалось выйти с честью из положения, т.к. производится просто последовательное копирование. А вот если бы надо было выборочно извлекать байты из массивов, то тут X-pointer уже не порулил бы совсем и код был бы действительно печальным.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 19 2006, 11:29
Сообщение #19


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Цитата(dxp @ Dec 19 2006, 09:52) *
Код, который вы показали, был характерен для IAR'овских компляторов версий 2.хх - они там упорно делали все подобные обращения в память через Z-pointer, что далеко не всегда хорошо, на что было указано и в версиях 3.хх уже ситуация изменилась к лучшему. Основная же причина сидит не в компиляторах, а в самом AVR, в котором мало (всего два) полноценных аппаратных регистра-указателя (Y и Z, X - неполноценный, у него отсутствует очень важный режим адресации со смещением). Т.е. один из указателей занят под указатель стека данных (еще один, мягко говоря, неудачный момент AVR - обо всех этих "фичах" AVR уже подробно говорилось, если интересно, поищите по форуму), остается один Z-pointer, который компилятор и пытается использовать. В данном случае удалось выйти с честью из положения, т.к. производится просто последовательное копирование. А вот если бы надо было выборочно извлекать байты из массивов, то тут X-pointer уже не порулил бы совсем и код был бы действительно печальным.


Совершенно верно, только приведенные здесь примеры относятся к компиллеру IAR 4.20a. Я сам удивляюсь, в программе много мест копирования массивов, и почти везде он все делает правильно. Копирование массивов с автоинкрементой регистров указателей. Особенно если большие массивы. Но бывают места, где оптимизатор "теряется" :-) Я ж не придумал это.
И еще напрягают попытки ИАРа по два раза считывать одну и ту же ячейку памяти при выполнении кода типа
Код
if(!a) a ++;
при отстутствующем спецификаторе volataile
А в общем, ИАР мне нравится. Но это ж не значит, что он не может быть лучше ;-)
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 19 2006, 23:17
Сообщение #20


Местный
***

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



Цитата(Perepic @ Dec 18 2006, 16:58) *
Цитата(rezident @ Nov 22 2006, 02:42) *

ИМХО потому что запись
Код
tmpByte <<= 1;

на самом деле краткая и обозначает
Код
tmpByte = tmpByte << 1;


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


Интересно мыслите, однако! Как вам такой пример, я честно говоря до сих пор не понимаю отчего IAR 4.11a так себя ведет. Оптимизация включена на максимум, окромя "cross-call"
Код
UCHAR TimeOut;            // глобальная переменная

__interrupt void TimerInt()
{
    if(TimeOut) TimeOut--;
};

Все это компилится в ледующий код:
Код
     LDS     R16, TimeOut
     TST     R16
     BREQ    0x392
  
    LDI     R30,0x9F
    LDI     R31,0x02
    LD      R16,Z
    DEC     R16
    ST      Z,R16

Сохраниение и восстановление стека я опустил.
Что мы видим? Грузим переменную, проверяем ее, если условие выполняется, опять ее же грузим (ЗАЧЕМ?), причем засоряя адресные регистры, модифицируем и сохраняем. В результате имеем 3 лишних комманды + 4 для сохраниения-восстановления адресных регистров. Более чем в 2 раза, однако! Никак оптимальным такой код не назовешь. Что скажете..?

Попробуйте так:
Код
     if (TimeOut)
           TimeOut -= 1;
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 20 2006, 08:16
Сообщение #21


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Цитата(_Bill @ Dec 19 2006, 23:17) *
Попробуйте так:
Код
     if (TimeOut)
           TimeOut -= 1;

Попробовал. Никакой разницы. Да оно в общем-то и понятно. Было бы удивительно, ведь с точки зрения "С" а--; и а -= 1; абсолютно идентичны.
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 20 2006, 11:50
Сообщение #22


Местный
***

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



Цитата(Perepic @ Dec 20 2006, 08:16) *
Цитата(_Bill @ Dec 19 2006, 23:17) *

Попробуйте так:
Код
     if (TimeOut)
           TimeOut -= 1;

Попробовал. Никакой разницы. Да оно в общем-то и понятно. Было бы удивительно, ведь с точки зрения "С" а--; и а -= 1; абсолютно идентичны.

Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Dec 21 2006, 02:12
Сообщение #23


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(_Bill @ Dec 20 2006, 11:50) *
Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость.


И вот на этой приятной ноте и хочется спросить, - а стоит ли применять такие методы?

Полазайте по форуму и Вы найдёте массу примеров таких ухищрений. Но в такой ситуации всегда остаётся вероятность того, что при смене версии компилятора или просто немного изменив окружающие операторы Вы, в следующей трансляции опять потеряете "золотую нить". Получается программирование на СИ с элементами ASMа. В том смысле что прога привязана к кристалу, сама к себе, к компилятору.

Например высказывание одного человека в форуме (примерно так) "... я групирую и увязываю связанные данные в структуры и в п/п передаю указатель на структуру... ...С массивами вообще не работаю... .... получается очень эффективно...". Я совершенно согласен с автором. Ничего сложного в этом нет. Понятно что можно обратится к элементу байтового массива Arr[i] или *(Arr[0]+i), но где у этого край??? Можно и умножение сдвигами заменить и двинутся дальше.

По идее эффективность работы с массивами должна после трансляции быть такой же как и при работе с указателями. Но этого нет. При больших массивах выигрыш от встроенной функции копирования или очистки массивов (приведенных выше) в разы! Очень существено. Хотя тот же компилятор запросто мог бы применить аналогичный приём!


И ещё никто не ответил мне на следующий вопрос. Почему при совершенно свободной Flash памяти и установленном максимальном уровне оптимизации по скорости компилятор генерит такое значительное колличество вспомогательных подпрограмм? Что я делаю не так и как этого избежать. Я же на них inline поставить не могу. Где это задаётся?

Мой пост прошу не относить к критическим в адрес компилятора. Компилятор мне нравится и претензий у меня к нему, фактически нет. Просто хочу лучше узнать его. И проанализировать разные подходы людей к программированию. Особенно учитывая Ваш опыт.

С уважением.
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 21 2006, 12:07
Сообщение #24


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Цитата(SasaVitebsk @ Dec 21 2006, 02:12) *
И ещё никто не ответил мне на следующий вопрос. Почему при совершенно свободной Flash памяти и установленном максимальном уровне оптимизации по скорости компилятор генерит такое значительное колличество вспомогательных подпрограмм? Что я делаю не так и как этого избежать. Я же на них inline поставить не могу. Где это задаётся?

Речь как я понял идет о перекрестных вызоывах. Полезная штука, кстати сказать, при незначительной потери в скорости, получается выигрыш от 10% и выше по объему кода. Одинаковые куски кода заменяются на подпрограммы. На этапе отладки я обычно отключаю. Ищите галочку "cross call" в закладке C++ -> Optimization.
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 21 2006, 16:30
Сообщение #25


Местный
***

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



Цитата(SasaVitebsk @ Dec 21 2006, 02:12) *
Цитата(_Bill @ Dec 20 2006, 11:50) *

Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость.


И вот на этой приятной ноте и хочется спросить, - а стоит ли применять такие методы?

Полазайте по форуму и Вы найдёте массу примеров таких ухищрений. Но в такой ситуации всегда остаётся вероятность того, что при смене версии компилятора или просто немного изменив окружающие операторы Вы, в следующей трансляции опять потеряете "золотую нить". Получается программирование на СИ с элементами ASMа. В том смысле что прога привязана к кристалу, сама к себе, к компилятору.

Тут нельзя сказать однозначно. Во-первых, мы так или иначе привязаны как контроллеру, с одной стороны, так и к инстументам для его программирования. И то, и другое нужно знать как можно лучше. Поэтому всякие эксперименты, позволяющие лучше узнать то, с чем работаешь, безусловно необходимы. Но...
Есть машинно-независимые способы оптимизации программ. Они всем известны. Это, прежде всего, более оптимальный алгоритм. Далее, выбор наиболее подходящей организации данных. Это и оптимизация программ на уровне ЯВУ. Опять же, понимание того, как компилятор генерирует код для тех или иных конструкций языка, даст возможность создать более оптимальную программу. Например, использование оператора do while является более оптимальным по сравнению с оператором while. Сравнение с нулем даст более оптимальный код, чем сравнении с константой. То есть
Код
      while (--i != 0) ...

более эффективно, чем
Код
      while (++i != CONST) ...

Таких примеров можно привести сколько угодно. Однако, эффективные программы часто получаются менее понятными и читабельными, особенно для посторонних людей. И если мы в погоне за оптимальностью напишем такой код, который будет труден для понимания и сопровождения, и (возможно) для переноса на другую платформу, а выигрыш даст лишь пару-другую инструкций, или пару микросекунд, то стоит ли тратить на это время? Если же скорость работы программы или ее размер являются критичными, то может лучше написать критичные по этим параметрам модули на ассемблере? И такие модули могут быть более понятными, поскольку программист использует все возможности архитектуры процессора. Ему не надо становиться на уши, чтобы описать с помощью инструкций процессора то, чего средствами Си описать или очень трудно, или вообще невозможно. Использование же всяких ассемблерных вставок, как правило, не дает той эффективности, какую желают получить, а программа становится бесформенной, трудной для понимания и сопровождения.
Короче говоря, во всем нужна мера.
Go to the top of the page
 
+Quote Post
HARMHARM
сообщение Dec 21 2006, 18:48
Сообщение #26


читатель даташитов
****

Группа: Свой
Сообщений: 853
Регистрация: 5-11-06
Из: Днепропетровск
Пользователь №: 21 999



Цитата(Perepic @ Dec 21 2006, 11:07) *
Цитата(SasaVitebsk @ Dec 21 2006, 02:12) *

И ещё никто не ответил мне на следующий вопрос. Почему при совершенно свободной Flash памяти и установленном максимальном уровне оптимизации по скорости компилятор генерит такое значительное колличество вспомогательных подпрограмм? Что я делаю не так и как этого избежать. Я же на них inline поставить не могу. Где это задаётся?

Речь как я понял идет о перекрестных вызоывах. Полезная штука, кстати сказать, при незначительной потери в скорости, получается выигрыш от 10% и выше по объему кода. Одинаковые куски кода заменяются на подпрограммы. На этапе отладки я обычно отключаю. Ищите галочку "cross call" в закладке C++ -> Optimization.


Я могу ошибаться, но речь идет о Function Inlining. Cross Call делает как раз "обратную" операцию - выносит из функций общие блоки в отдельные вызовы.
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Dec 26 2006, 11:15
Сообщение #27


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(HARMHARM @ Dec 21 2006, 17:48) *
Цитата(Perepic @ Dec 21 2006, 11:07) *

Цитата(SasaVitebsk @ Dec 21 2006, 02:12) *

И ещё никто не ответил мне на следующий вопрос. Почему при совершенно свободной Flash памяти и установленном максимальном уровне оптимизации по скорости компилятор генерит такое значительное колличество вспомогательных подпрограмм? Что я делаю не так и как этого избежать. Я же на них inline поставить не могу. Где это задаётся?

Речь как я понял идет о перекрестных вызоывах. Полезная штука, кстати сказать, при незначительной потери в скорости, получается выигрыш от 10% и выше по объему кода. Одинаковые куски кода заменяются на подпрограммы. На этапе отладки я обычно отключаю. Ищите галочку "cross call" в закладке C++ -> Optimization.


Я могу ошибаться, но речь идет о Function Inlining. Cross Call делает как раз "обратную" операцию - выносит из функций общие блоки в отдельные вызовы.

Вы действительно ошибаетесь.
Речь была о том, что cross call оптимизацию предлагается отключить, чтобы компилятор не создавал много вложенных функций. При максимальном уровне оптимизации эта опция включена по умолчанию.
Что касается Function Inlining, то это относится к пользовательским функциям. Если компилятор сочтёт их достаточно короткими, то он их инлайнит.
Go to the top of the page
 
+Quote Post
Rst7
сообщение Dec 26 2006, 16:09
Сообщение #28


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

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



Цитата(Perepic @ Dec 18 2006, 15:58) *
Интересно мыслите, однако! Как вам такой пример, я честно говоря до сих пор не понимаю отчего IAR 4.11a так себя ведет. Оптимизация включена на максимум, окромя "cross-call"
Код
UCHAR TimeOut;            // глобальная переменная

__interrupt void TimerInt()
{
    if(TimeOut) TimeOut--;
};


В принципе, я придерживаюсь мнения, что компилятору надо подсказывать, что делать. А также помнить об особеностях процессора - в данном случае не надо забывать, что у нас не аккумуляторная машина, и регистров валом. Имеет смысл написать так:
Код
char TimeOut;            // ãëîáàëüíàÿ ïåðåìåííàÿ

__interrupt void TimerInt()
{
  char to=TimeOut;
  if (to) TimeOut=--to;
}


В результате имеем нормальный код:
Код
    294            char to=TimeOut;
   \   00000006   9100....           LDS     R16, TimeOut
    295            if (to) TimeOut=--to;
   \   0000000A   2300               TST     R16
   \   0000000C   F019               BREQ    ??TimerInt_0
   \   0000000E   950A               DEC     R16
   \   00000010   9300....           STS     TimeOut, R16
    296          };
   \                     ??TimerInt_0:


Да, я понимаю, хотелось бы, чтобы компилятор сам это делал... Но с другой стороны, если лень-матушка, программируйте на Делфи для большого брата, вообще не надо думать...


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 26 2006, 16:27
Сообщение #29


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Rst7 @ Dec 26 2006, 15:09) *
Имеет смысл написать так:
Код
  char to=TimeOut;

Если уж подсказывать, то подсказывать по полной программе:
Код
register char to=TimeOut;


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
Rst7
сообщение Dec 26 2006, 16:31
Сообщение #30


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

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



Цитата(zltigo @ Dec 26 2006, 15:27) *
Цитата(Rst7 @ Dec 26 2006, 15:09) *

Имеет смысл написать так:
Код
  char to=TimeOut;

Если уж подсказывать, то подсказывать по полной программе:
Код
register char to=TimeOut;



Согласен. Это уже полный портабл...


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
Perepic
сообщение Dec 27 2006, 08:44
Сообщение #31


Участник
*

Группа: Участник
Сообщений: 23
Регистрация: 14-08-06
Пользователь №: 19 528



Цитата(Rst7 @ Dec 26 2006, 16:09) *
В принципе, я придерживаюсь мнения, что компилятору надо подсказывать, что делать. А также помнить об особеностях процессора - в данном случае не надо забывать, что у нас не аккумуляторная машина, и регистров валом. Имеет смысл написать так:
Код
char TimeOut;            // ãëîáàëüíàÿ ïåðåìåííàÿ

__interrupt void TimerInt()
{
  char to=TimeOut;
  if (to) TimeOut=--to;
}

Да, я понимаю, хотелось бы, чтобы компилятор сам это делал... Но с другой стороны, если лень-матушка, программируйте на Делфи для большого брата, вообще не надо думать...

Хе-хе. И правда в таком случае IAR все делает грамотно. Вот только читабельность кода страдает. Наверно и вправду чем быстрее код - тем ближе к ассемблеру :-)

PS: всех с наступающим!
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 27 2006, 10:27
Сообщение #32


Местный
***

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



Цитата(zltigo @ Dec 26 2006, 16:27) *
Цитата(Rst7 @ Dec 26 2006, 15:09) *

Имеет смысл написать так:
Код
  char to=TimeOut;

Если уж подсказывать, то подсказывать по полной программе:
Код
register char to=TimeOut;


Вообще-то, IAR игнорирует ключевое слово register. Или нет?
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Dec 27 2006, 14:18
Сообщение #33


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(_Bill @ Dec 27 2006, 09:27) *
Вообще-то, IAR игнорирует ключевое слово register. Или нет?

Может игнорировать если нельзя обеспечить.
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 27 2006, 14:48
Сообщение #34


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(IgorKossak @ Dec 27 2006, 17:18) *
Цитата(_Bill @ Dec 27 2006, 09:27) *

Вообще-то, IAR игнорирует ключевое слово register. Или нет?

Может игнорировать если нельзя обеспечить.

Причем игнорировать молча. Иными словами, если можно обеспечить, то и так задействует регистр, если нельзя, то не задействует, ничего не сообщая. Так сегодня поступает подавляющее большинство (если не все) компиляторов. От ключевого слова register ничего не зависит, оно является рудиментом и артефактом. Оставленным в языке для совместимости со старым кодом. Есть не просит, пусть будет.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 27 2006, 15:41
Сообщение #35


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(dxp @ Dec 27 2006, 13:48) *
Иными словами, если можно обеспечить, то и так задействует регистр, если нельзя, то не задействует, ничего не сообщая.

Верно, НО! если на всех регистров не хватает, то тут оно и сработает отдав предпочтение подсказке.
Использую довольно часто часто в сложных конструкциях - меня не затрудняет подсказать и компилятор тоже не напрягает smile.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
_Bill
сообщение Dec 27 2006, 19:03
Сообщение #36


Местный
***

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



Цитата(dxp @ Dec 27 2006, 14:48) *
Цитата(IgorKossak @ Dec 27 2006, 17:18) *

Цитата(_Bill @ Dec 27 2006, 09:27) *

Вообще-то, IAR игнорирует ключевое слово register. Или нет?

Может игнорировать если нельзя обеспечить.

Причем игнорировать молча. Иными словами, если можно обеспечить, то и так задействует регистр, если нельзя, то не задействует, ничего не сообщая. Так сегодня поступает подавляющее большинство (если не все) компиляторов. От ключевого слова register ничего не зависит, оно является рудиментом и артефактом. Оставленным в языке для совместимости со старым кодом. Есть не просит, пусть будет.

Это не совсем так. Просто в IAR сделано именно так. Где размещать переменные решает только компилятор. В других средах (например, в Borland) имеется возможность выбора: не размещать переменные в регистрах, размещать автоматически или размещать по ключевому слову register. Сейчас, когда ресурсов в PC предостаточно, компиляторы стали достаточно "умными", то необходимость в использовании register как бы отпадает. Но в контроллерах с ограниченными ресурсами иногда желательно дать возможность решать вопрос о размещении переменных самому программисту.
Go to the top of the page
 
+Quote Post
dxp
сообщение Dec 28 2006, 07:32
Сообщение #37


Adept
******

Группа: Свой
Сообщений: 3 469
Регистрация: 6-12-04
Из: Novosibirsk
Пользователь №: 1 343



Цитата(_Bill @ Dec 27 2006, 22:03) *
Это не совсем так. Просто в IAR сделано именно так. Где размещать переменные решает только компилятор. В других средах (например, в Borland) имеется возможность выбора: не размещать переменные в регистрах, размещать автоматически или размещать по ключевому слову register.

И как, например, запретить размещать переменную в регистре? Какое ключевое слово для этого используется?

Цитата(_Bill @ Dec 27 2006, 22:03) *
Сейчас, когда ресурсов в PC предостаточно, компиляторы стали достаточно "умными", то необходимость в использовании register как бы отпадает. Но в контроллерах с ограниченными ресурсами иногда желательно дать возможность решать вопрос о размещении переменных самому программисту.

Борланд - это PC. Неужто в нем недостаток регистров? Ни разу не встречал в коде для Борланда (начиная с версий оного 4 и выше) подобных попыток оптимизаций.

Имхо, уже давным давно прошла необходимость рулить такими оптимизациями из С-кода. Компилятор с этим разберется лучше. Программисту надо состредоточиться на алгоритме, а уж как по регистрам совать - тут все карты на руках у компилятора. Если хочется адекватного результата ручному контролю, то это ассемблер (вызов функции или вставки).

Кроме IAR, еще несколько компиляторов не замечены во внимании к ключевому слову register: CCS/TMS320F28xx, VDSP++/Blackfin, avr-gcc (правда, с последним знакомство поверхностное).

P.S. Посмотрел в доку на Билдер:

Цитата
Category

Storage class specifiers

Syntax

register <data definition> ;

Description

Use the register storage class specifier to store the variable being declared in a CPU register (if possible), to optimize access and reduce code.

Note: The C++Builder compiler can ignore requests for register allocation. Register allocation is based on the compiler’s analysis of how a variable is used.


--------------------
«Отыщи всему начало, и ты многое поймёшь» К. Прутков
Go to the top of the page
 
+Quote Post
zltigo
сообщение Dec 28 2006, 12:13
Сообщение #38


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(dxp @ Dec 28 2006, 06:32) *
И как, например, запретить размещать переменную в регистре? Какое ключевое слово для этого используется?

-r-
Про Builder, правда ничего не скажу и отключением никогда не пользовался и пользоваться не буду smile.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение Dec 28 2006, 12:29
Сообщение #39


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Цитата(dxp @ Dec 28 2006, 06:32) *
И как, например, запретить размещать переменную в регистре? Какое ключевое слово для этого используется?

Насколько мне известно в IAR такого вообще нет.
Но можно заблокировать регистр или группу регистров от использования вообще (в настройках проекта), но это чревато проблемами с библиотеками. В любом случае надо очень внимательно читать последнюю документацию о том сколько регистров можно заблокировать.
Go to the top of the page
 
+Quote Post
_Bill
сообщение Jan 2 2007, 22:33
Сообщение #40


Местный
***

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



Цитата(dxp @ Dec 28 2006, 07:32) *
И как, например, запретить размещать переменную в регистре? Какое ключевое слово для этого используется?

Цитата(_Bill @ Dec 27 2006, 22:03) *

Сейчас, когда ресурсов в PC предостаточно, компиляторы стали достаточно "умными", то необходимость в использовании register как бы отпадает. Но в контроллерах с ограниченными ресурсами иногда желательно дать возможность решать вопрос о размещении переменных самому программисту.

Борланд - это PC. Неужто в нем недостаток регистров? Ни разу не встречал в коде для Борланда (начиная с версий оного 4 и выше) подобных попыток оптимизаций.

Имхо, уже давным давно прошла необходимость рулить такими оптимизациями из С-кода. Компилятор с этим разберется лучше. Программисту надо состредоточиться на алгоритме, а уж как по регистрам совать - тут все карты на руках у компилятора. Если хочется адекватного результата ручному контролю, то это ассемблер (вызов функции или вставки).

Кроме IAR, еще несколько компиляторов не замечены во внимании к ключевому слову register: CCS/TMS320F28xx, VDSP++/Blackfin, avr-gcc (правда, с последним знакомство поверхностное).

P.S. Посмотрел в доку на Билдер:

Цитата
Category

Storage class specifiers

Syntax

register <data definition> ;

Description

Use the register storage class specifier to store the variable being declared in a CPU register (if possible), to optimize access and reduce code.

Note: The C++Builder compiler can ignore requests for register allocation. Register allocation is based on the compiler’s analysis of how a variable is used.


В Borland C++ в проекте можно указания опции для использования регистровых переменных:
None, Automatic и Register keyword. Т.е. в первом случае компилятор не будет размещать переменные в регистрах, во втором случае он будет размещать переменные в регистрах автоматически как только он сочтет это нужным. В третьем случае в регистрах будут размещаться только те переменные, для которых указан класс памяти register.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jan 4 2007, 00:22
Сообщение #41


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(dxp @ Dec 28 2006, 08:32) *
Борланд - это PC. Неужто в нем недостаток регистров? Ни разу не встречал в коде для Борланда (начиная с версий оного 4 и выше) подобных попыток оптимизаций.


Похоже Вы немного пошутили или не то имели ввиду. biggrin.gif По сравнению с AVR в PC регистров почти нет. biggrin.gif

А если учитывать, что часть из них связано с определёнными функциями (CX - регистр счётчик, BX,EX -базы, AX - аккумулятор). То такая оптимизация вообще не имеет смысла. Да и при таком построении процессора, вопрос такой экономии не ставится. Там оптимизация строится на базе совершенно других принципов. Длина цикла - размер кэша - объём данных по работе с памятью, "грамотное обращение" к переферии и т.д.
Go to the top of the page
 
+Quote Post
_Bill
сообщение Jan 4 2007, 23:20
Сообщение #42


Местный
***

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



Цитата(SasaVitebsk @ Jan 4 2007, 00:22) *
Цитата(dxp @ Dec 28 2006, 08:32) *

Борланд - это PC. Неужто в нем недостаток регистров? Ни разу не встречал в коде для Борланда (начиная с версий оного 4 и выше) подобных попыток оптимизаций.


Похоже Вы немного пошутили или не то имели ввиду. biggrin.gif По сравнению с AVR в PC регистров почти нет. biggrin.gif

А если учитывать, что часть из них связано с определёнными функциями (CX - регистр счётчик, BX,EX -базы, AX - аккумулятор). То такая оптимизация вообще не имеет смысла. Да и при таком построении процессора, вопрос такой экономии не ставится. Там оптимизация строится на базе совершенно других принципов. Длина цикла - размер кэша - объём данных по работе с памятью, "грамотное обращение" к переферии и т.д.

Не стоит забывать, что эти регистры 32-разрядные. И есть возможность использовать их и как 16-, и как 8-разрядные. К тому же, у AVR есть определенные проблемы с использованием младших 16 регистров. Так что реально используются только 16 старших регистров. А если требуются данные типа long или float, так их останется на все про все всего 4. И опять же, у PC инструкции позволяют оперировать с ячейками памяти как с регистрами (при увеличении длины инструкции и времени ее выполнения). Так что вопросы оптимизации программы за счет использования регистров остаются весьма актуальными.
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение Jan 5 2007, 03:58
Сообщение #43


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Цитата(_Bill @ Jan 5 2007, 00:20) *
Не стоит забывать, что эти регистры 32-разрядные. И есть возможность использовать их и как 16-, и как 8-разрядные. К тому же, у AVR есть определенные проблемы с использованием младших 16 регистров. Так что реально используются только 16 старших регистров. А если требуются данные типа long или float, так их останется на все про все всего 4. И опять же, у PC инструкции позволяют оперировать с ячейками памяти как с регистрами (при увеличении длины инструкции и времени ее выполнения). Так что вопросы оптимизации программы за счет использования регистров остаются весьма актуальными.


Ну это скорее желаемое чем действительное. smile.gif Регистры действительно 32-ух битные, но их нельзя использовать, например как 2 16-ти битных или 4 - восьми битных. Если говорить о "определённых проблемах по использованию отдельных регистров", то здесь INTEL явно лидирует. Например сложить B и С Вам не удастся. Если же Вы попытаетесь написать реальную прогу, даже на ассемблере, длиной хотябы листа два, используя расширенные команды, то Вам врятли удастся съэкономить даже один регистр. А компилятор даже не будет пытаться это делать.
Но это и не нужно. Вы совершенно правы, во второй части. INTEL имеет развитой механизм работы с памятью. Учитывая все мыслимые способы адресации. А сама архитектура (кэш буфер данных) позволяет к значительным массивам используемых данных обращаться, фактически как к регистрам. Кроме кэша данных есть кэш программы, что накладывает свои особенности. Ну и наконец, наличие нескольких ALU (в пнях уже по-моему 2-целочисленных и 1 с плавающей запятой) - тоже имеет значение. Поэтому оптимизация программ там имеет совершенно другие принципы и особенности. Согласно литературе это всё учитывается компиляторами. Я читал, что в Windows используются циклы определённой длины, а компилятор прогу делает так, что бы распаралеливание было максимальным.

Но я, боже упаси, не собираюсь затевать спор в той области, где имею поверхностные знания. Я просто пошутил. biggrin.gif Очевидно что само число регистров - просто крайне мало. dxp, думаю, явно имел ввиду не регистры, а сам принцип экономии таким способом. И я его тут полностью поддерживаю. Просто выразился неудачно. А я пошутил. biggrin.gif Надеюсь никого не обидел.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Jan 7 2007, 01:33
Сообщение #44


Гуру
******

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



Цитата(zltigo @ Dec 27 2006, 14:41) *
Цитата(dxp @ Dec 27 2006, 13:48) *

Иными словами, если можно обеспечить, то и так задействует регистр, если нельзя, то не задействует, ничего не сообщая.

Верно, НО! если на всех регистров не хватает, то тут оно и сработает отдав предпочтение подсказке.
Именно, что верно. А "НО" не верно. Зато верно поскипанное:
Цитата(dxp @ Dec 27 2006, 13:48) *
От ключевого слова register ничего не зависит
Читая документацию случайно наткнулся. EWAVR_Compiler reference-> Implementation-defined behavior-> REGISTERS:
Цитата
Honoring the register keyword (6.5.1)
User requests for register variables are not honored.
То же самое и в доке на ARM.
P.S. Так что зря мы тут копья ломали, все ответы - они в доке, только нужно знать, где искать. А чтобы знать, нужно сначала ее прочитать. Только кто ж ее читает, от корки до корки sad.gif ?


--------------------
На любой вопрос даю любой ответ
"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
zltigo
сообщение Jan 7 2007, 02:03
Сообщение #45


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



Цитата(Сергей Борщ @ Jan 7 2007, 00:33) *
P.S. Так что зря мы тут копья ломали, все ответы - они в доке, только нужно знать, где искать.

Ну положим совсем не зря:
-Ключевое слово существует.
-Некоторыми компиляторами игнорируется.
-Некоторыми - нет.
-Иcпользование как минимум не помешает.
Цитата
А чтобы знать, нужно сначала ее прочитать. Только кто ж ее читает, от корки до корки ?

Ну а документацию - документацию надо читать именно упорно от корки до корки. Я обычно перед сном раньше читал, последние годы как-то и на сон не хватает sad.gif.


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post

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

 


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


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