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

 
 
> Компилятор в 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
Ответов (15 - 29)
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

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

 


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


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