|
|
  |
Странное поведение компилятора AVRGCC в простой ситуации |
|
|
|
Mar 28 2009, 13:54
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 29-12-04
Пользователь №: 1 738

|
Добрый всем вечер.
Столкнулся со странным поведением компилятора в простой ситуации. Имеется простой код:
volatile char data;
int main(void){ if((data & 3) == 0) data++;
return(0); }
после компиляции имеем листинг:
volatile char data;
int main(void){ if((data & 3) == 0) 5e: 80 91 60 00 lds r24, 0x0060 62: 90 e0 ldi r25, 0x00 ; 0 64: 83 70 andi r24, 0x03 ; 3 66: 90 70 andi r25, 0x00 ; 0 68: 89 2b or r24, r25 6a: 29 f4 brne .+10 ; 0x76 <main+0x18> data++; 6c: 80 91 60 00 lds r24, 0x0060 70: 8f 5f subi r24, 0xFF ; 255 72: 80 93 60 00 sts 0x0060, r24
return(0); } 76: 80 e0 ldi r24, 0x00 ; 0 78: 90 e0 ldi r25, 0x00 ; 0 7a: 08 95 ret
видно, что в данном случае константу компилятор интерпретирует как 16 битную и никакие приведения типа не помогают. Однако если изменить константу на значение 9, то всё нормально, вот листинг :
volatile char data;
int main(void){ if((data & 9) == 0) 5e: 80 91 60 00 lds r24, 0x0060 62: 89 70 andi r24, 0x09 ; 9 64: 29 f4 brne .+10 ; 0x70 <main+0x12> data++; 66: 80 91 60 00 lds r24, 0x0060 6a: 8f 5f subi r24, 0xFF ; 255 6c: 80 93 60 00 sts 0x0060, r24
return(0); } 70: 80 e0 ldi r24, 0x00 ; 0 72: 90 e0 ldi r25, 0x00 ; 0 74: 08 95 ret
при константе равной 15 опять воспринимает как 16 битное. Путём подбора констант заметил, что до 8 включительно воспринимает как 16 битное, затем с 9 как 8 битное. То есть какая то зависимость от значения. Вопрос . Кто нибудь сталкивался с подобным? Может это ошибка в компиляторе хотя она не очень значительная, ведь с точки зрения кода всё правильно, только имеют место ненужные команды. В слуае критичности по размеру кода и количеству таких ситуаций несколько увеличивается размер кода. Спасибо.
|
|
|
|
|
Mar 28 2009, 14:34
|
Участник

Группа: Участник
Сообщений: 19
Регистрация: 29-12-04
Пользователь №: 1 738

|
Цитата(demiurg_spb @ Mar 28 2009, 17:14)  Какая версия компилятора? Какой уровень оптимизации?
А а если так: volatile unsigned char data; if ( !(data&3U) ) {...} или if ( !(data&(unsigned char)3) ) {...} или if ( !(unsigned char)(data&(unsigned char)3) ) {...} Версия компилятор 20081205, оптимизация Os . К сожалению приведение типа не помогает, пробовал по разному. От версии компилятора помоему это не зависит
|
|
|
|
|
Mar 28 2009, 16:10
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(Олег. @ Mar 28 2009, 15:54)  Столкнулся со странным поведением компилятора в простой ситуации. Увы, есть такая беда. Радикально помогает только введение промежуточной переменной. Код volatile char data;
void foo(void){ char tmp = data & 3; if(tmp == 0) data++; } И уж она-то будет соптимизиована (т.е. лишнее место занимать не будет, а операции станут 8-битными) Код .global foo .type foo, @function foo: /* prologue: frame size=0 */ /* prologue end (size=0) */ lds r24,data andi r24,lo8(3) brne .L4 lds r24,data subi r24,lo8(-(1)) sts data,r24 .L4: ret /* epilogue: frame size=0 */
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 28 2009, 20:46
|

Нечётный пользователь.
     
Группа: Свой
Сообщений: 2 033
Регистрация: 26-05-05
Из: Бровари, Україна
Пользователь №: 5 417

|
Цитата(_Pasha @ Mar 28 2009, 18:54)  Я понял такую вещь, что это не беда никакая. Раз volatile не оптимизируется, то и вычисление логических выражений не оптимизируется. В данном случае тип результата логического выражения будет int, а надо бы int8_fast_t  В данном случае volatile ни при чём, без него тот же эффект, только в профиль. Код char data;
void foo(void) { char tmp = data & 3; if(tmp == 0) data++; }
void moo(void){ if( (data & 3) == 0) data++; } Код foo: lds r25,data mov r24,r25 andi r24,lo8(3) brne .L4 subi r25,lo8(-(1)) sts data,r25 .L4: ret
moo: lds r18,data mov r24,r18 clr r25 sbrc r24,7 com r25 andi r24,lo8(3) andi r25,hi8(3) or r24,r25 brne .L13 subi r18,lo8(-(1)) sts data,r18 .L13: ret
--------------------
Ну, я пошёл… Если что – звоните…
|
|
|
|
|
Mar 29 2009, 11:07
|

Частый гость
 
Группа: Свой
Сообщений: 91
Регистрация: 10-10-07
Из: Воронежа
Пользователь №: 31 250

|
Недавно тоже столкнулся с этим. Пробовал разными версиями компиляторов - результат один и тот же. Так же методом проб и ошибок выяснил, что наличие этих "лишних движений" может зависить от значений констант, иногда от порядка проведения операций над переменными наличия скобок. Введение промежуточных переменных чаще всего помогало, но не всегда. В общем решил проблему с помощью инлайн-ассемблера, конечно это заморочно, но зато добился таки полного отсутствия мусора в критических секциях.
Кстати, наблюдал еще одну фишку - бессмысленное перекладывание переменных из регистра в регистр и обратно, метод устранения тот же, что и для вышеописанного бага - введение временных переменых и разбиение сложных выражений на простые операции. Четкой закономерности найти не удалось. Да, и еще этот феномен как правило сопровождается сохранением в стеке регистров, без которых можно было-бы обойтись, что может здорово увеличить размер кода и время выполнения небольших функций. В данных случаях volatile-переменные нигде не использовал.
--------------------
- Бендер, ты же робот, зачем тебе пить пиво? - Незачем! Я могу бросить в любой момент!
|
|
|
|
|
  |
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|