|
Компилятор в IAR, ньюансы обращения к переменным |
|
|
|
Nov 22 2006, 02:23
|
Местный
  
Группа: Свой
Сообщений: 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 Спасибо заранее!
|
|
|
|
|
 |
Ответов
|
Nov 22 2006, 02:42
|
Гуру
     
Группа: Свой
Сообщений: 10 920
Регистрация: 5-04-05
Пользователь №: 3 882

|
ИМХО потому что запись Код tmpByte <<= 1; на самом деле краткая и обозначает Код tmpByte = tmpByte << 1; Аналогично Код tmpByte |= tmp_bit; обозначает Код tmpByte = tmpByte | tmp_bit; Поскольку tmpByte является и источником-операндом и приемником результата, то компилятор вполне логично каждую команду раскладывает так, как ему предписано. А вот с включенной оптимизацией он возможно соптимизирует код к такому виду, который вы считаете нормальным.
|
|
|
|
|
Dec 18 2006, 16:58
|
Участник

Группа: Участник
Сообщений: 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 раза, однако! Никак оптимальным такой код не назовешь. Что скажете..?
|
|
|
|
|
Dec 19 2006, 23:17
|
Местный
  
Группа: Участник
Сообщений: 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;
|
|
|
|
|
Dec 20 2006, 08:16
|
Участник

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

|
Цитата(_Bill @ Dec 19 2006, 23:17)  Попробуйте так: Код if (TimeOut) TimeOut -= 1; Попробовал. Никакой разницы. Да оно в общем-то и понятно. Было бы удивительно, ведь с точки зрения "С" а--; и а -= 1; абсолютно идентичны.
|
|
|
|
|
Dec 20 2006, 11:50
|
Местный
  
Группа: Участник
Сообщений: 416
Регистрация: 18-04-06
Из: Челябинск
Пользователь №: 16 219

|
Цитата(Perepic @ Dec 20 2006, 08:16)  Цитата(_Bill @ Dec 19 2006, 23:17)  Попробуйте так: Код if (TimeOut) TimeOut -= 1; Попробовал. Никакой разницы. Да оно в общем-то и понятно. Было бы удивительно, ведь с точки зрения "С" а--; и а -= 1; абсолютно идентичны. Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость.
|
|
|
|
|
Dec 21 2006, 02:12
|
Гуру
     
Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521

|
Цитата(_Bill @ Dec 20 2006, 11:50)  Все правильно. Только компиляторы разные семантически одинаковые конструкции иногда транслируют по-разному. Поэтому всегда имеет смысл "повертеть" такую конструкцию с тем, чтобы увидеть в каких случаях компилятор сгенерирует наиболее оптимальный код. Если, конечно, есть в этом необходимость. И вот на этой приятной ноте и хочется спросить, - а стоит ли применять такие методы? Полазайте по форуму и Вы найдёте массу примеров таких ухищрений. Но в такой ситуации всегда остаётся вероятность того, что при смене версии компилятора или просто немного изменив окружающие операторы Вы, в следующей трансляции опять потеряете "золотую нить". Получается программирование на СИ с элементами ASMа. В том смысле что прога привязана к кристалу, сама к себе, к компилятору. Например высказывание одного человека в форуме (примерно так) "... я групирую и увязываю связанные данные в структуры и в п/п передаю указатель на структуру... ...С массивами вообще не работаю... .... получается очень эффективно...". Я совершенно согласен с автором. Ничего сложного в этом нет. Понятно что можно обратится к элементу байтового массива Arr[i] или *(Arr[0]+i), но где у этого край??? Можно и умножение сдвигами заменить и двинутся дальше. По идее эффективность работы с массивами должна после трансляции быть такой же как и при работе с указателями. Но этого нет. При больших массивах выигрыш от встроенной функции копирования или очистки массивов (приведенных выше) в разы! Очень существено. Хотя тот же компилятор запросто мог бы применить аналогичный приём! И ещё никто не ответил мне на следующий вопрос. Почему при совершенно свободной Flash памяти и установленном максимальном уровне оптимизации по скорости компилятор генерит такое значительное колличество вспомогательных подпрограмм? Что я делаю не так и как этого избежать. Я же на них inline поставить не могу. Где это задаётся? Мой пост прошу не относить к критическим в адрес компилятора. Компилятор мне нравится и претензий у меня к нему, фактически нет. Просто хочу лучше узнать его. И проанализировать разные подходы людей к программированию. Особенно учитывая Ваш опыт. С уважением.
|
|
|
|
|
Dec 21 2006, 16:30
|
Местный
  
Группа: Участник
Сообщений: 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) ... Таких примеров можно привести сколько угодно. Однако, эффективные программы часто получаются менее понятными и читабельными, особенно для посторонних людей. И если мы в погоне за оптимальностью напишем такой код, который будет труден для понимания и сопровождения, и (возможно) для переноса на другую платформу, а выигрыш даст лишь пару-другую инструкций, или пару микросекунд, то стоит ли тратить на это время? Если же скорость работы программы или ее размер являются критичными, то может лучше написать критичные по этим параметрам модули на ассемблере? И такие модули могут быть более понятными, поскольку программист использует все возможности архитектуры процессора. Ему не надо становиться на уши, чтобы описать с помощью инструкций процессора то, чего средствами Си описать или очень трудно, или вообще невозможно. Использование же всяких ассемблерных вставок, как правило, не дает той эффективности, какую желают получить, а программа становится бесформенной, трудной для понимания и сопровождения. Короче говоря, во всем нужна мера.
|
|
|
|
Сообщений в этой теме
king2 Компилятор в IAR Nov 22 2006, 02:23 king2 А почему оно в одном случае загружает переменную и... Nov 22 2006, 03:26  IgorKossak Цитата(king2 @ Nov 22 2006, 02:26) А поче... Nov 22 2006, 10:50   dxp ЦитатаЦитата(king2 @ Nov 22 2006, 02:26) ... Nov 22 2006, 11:57      Perepic Цитата(SasaVitebsk @ Dec 21 2006, 02:12) ... Dec 21 2006, 12:07       HARMHARM Цитата(Perepic @ Dec 21 2006, 11:07) Цита... Dec 21 2006, 18:48        IgorKossak Цитата(HARMHARM @ Dec 21 2006, 17:48) Цит... Dec 26 2006, 11:15  Rst7 Цитата(Perepic @ Dec 18 2006, 15:58) Инте... Dec 26 2006, 16:09   zltigo Цитата(Rst7 @ Dec 26 2006, 15:09) Имеет с... Dec 26 2006, 16:27    Rst7 Цитата(zltigo @ Dec 26 2006, 15:27) Цитат... Dec 26 2006, 16:31    _Bill Цитата(zltigo @ Dec 26 2006, 16:27) Цитат... Dec 27 2006, 10:27     IgorKossak Цитата(_Bill @ Dec 27 2006, 09:27) Вообще... Dec 27 2006, 14:18      dxp Цитата(IgorKossak @ Dec 27 2006, 17:18) Ц... Dec 27 2006, 14:48       zltigo Цитата(dxp @ Dec 27 2006, 13:48) Иными сл... Dec 27 2006, 15:41        Сергей Борщ Цитата(zltigo @ Dec 27 2006, 14:41) Цитат... Jan 7 2007, 01:33         zltigo Цитата(Сергей Борщ @ Jan 7 2007, 00:33) P... Jan 7 2007, 02:03       _Bill Цитата(dxp @ Dec 27 2006, 14:48) Цитата(I... Dec 27 2006, 19:03        dxp Цитата(_Bill @ Dec 27 2006, 22:03) Это не... Dec 28 2006, 07:32         zltigo Цитата(dxp @ Dec 28 2006, 06:32) И как, н... Dec 28 2006, 12:13          IgorKossak Цитата(dxp @ Dec 28 2006, 06:32) И как, н... Dec 28 2006, 12:29         _Bill Цитата(dxp @ Dec 28 2006, 07:32) И как, н... Jan 2 2007, 22:33         SasaVitebsk Цитата(dxp @ Dec 28 2006, 08:32) Борланд ... Jan 4 2007, 00:22          _Bill Цитата(SasaVitebsk @ Jan 4 2007, 00:22) Ц... Jan 4 2007, 23:20           SasaVitebsk Цитата(_Bill @ Jan 5 2007, 00:20) Не стои... Jan 5 2007, 03:58   Perepic Цитата(Rst7 @ Dec 26 2006, 16:09) В принц... Dec 27 2006, 08:44 SasaVitebsk На этот раз для меня не понятный момент. До этого ... Dec 7 2006, 23:06 rezident Цитата(SasaVitebsk @ Dec 8 2006, 01:06) С... Dec 8 2006, 01:01  zltigo Цитата(rezident @ Dec 8 2006, 00:01) заме... Dec 8 2006, 02:52 SasaVitebsk Информация к размышлению. Объявление не менял. Пом... Dec 8 2006, 03:12 _Bill Цитата(SasaVitebsk @ Dec 8 2006, 03:12) И... Dec 8 2006, 12:16  SasaVitebsk Цитата(_Bill @ Dec 8 2006, 12:16) Все пра... Dec 8 2006, 13:24   _Bill Цитата(SasaVitebsk @ Dec 8 2006, 13:24) В... Dec 8 2006, 17:31 SasaVitebsk Спасибо, разъяснили доступно. Извините за наглость... Dec 11 2006, 21:34 zltigo Цитата(SasaVitebsk @ Dec 11 2006, 20:34) ... Dec 11 2006, 22:38 Perepic Или вот еще, тоже шедевр. Блин, чем больше в дизас... Dec 18 2006, 18:01 dxp Цитата(Perepic @ Dec 18 2006, 21:01) Или ... Dec 19 2006, 09:52  Perepic Цитата(dxp @ Dec 19 2006, 09:52) Код, кот... Dec 19 2006, 11:29 SasaVitebsk Тем не менее местами просто сказка и песня! ... Dec 18 2006, 23:36
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|