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

 
 
 
Reply to this topicStart new topic
> Препроцессор не хочет вычислять константные выражения, WinAVR-20090313
injen-d
сообщение Jul 25 2009, 11:14
Сообщение #1


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

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



Вот пример:
Код
#include <avr/io.h>

class DELAY{
    public:
    const uint8_t Cadd;
    volatile uint8_t& port;

    DELAY(const uint8_t c, volatile uint8_t& p):Cadd(c), port(p)
    {
        if ((Cadd%3)==0) asm volatile ("nop\n\t");
        if ((Cadd%3)==1) asm volatile ("nop\n\t" "nop\n\t");
        if ((Cadd%3)==2) asm volatile ("nop\n\t" "nop\n\t" "nop\n\t");
        port=c;
    }
};

int main(void)
{
    DELAY mod1(4,PORTA);
    DELAY mod2(5,PORTB);

    while(1);
    return 0;
}

в результате:
Код
...
0000006c <_ZN5DELAYC1EhRVh>:
  6c:    fc 01           movw    r30, r24
  6e:    26 2f           mov    r18, r22
  70:    da 01           movw    r26, r20
  72:    60 83           st    Z, r22
  74:    52 83           std    Z+2, r21; 0x02
  76:    41 83           std    Z+1, r20; 0x01
  78:    86 2f           mov    r24, r22
  7a:    63 e0           ldi    r22, 0x03; 3
  7c:    0e 94 66 00     call    0xcc; 0xcc <__udivmodqi4>
  80:    99 23           and    r25, r25
  82:    11 f4           brne    .+4      ; 0x88 <_ZN5DELAYC1EhRVh+0x1c>
  84:    00 00           nop
  86:    0a c0           rjmp    .+20     ; 0x9c <_ZN5DELAYC1EhRVh+0x30>
  88:    91 30           cpi    r25, 0x01; 1
  8a:    19 f4           brne    .+6      ; 0x92 <_ZN5DELAYC1EhRVh+0x26>
  8c:    00 00           nop
  8e:    00 00           nop
  90:    05 c0           rjmp    .+10     ; 0x9c <_ZN5DELAYC1EhRVh+0x30>
  92:    92 30           cpi    r25, 0x02; 2
  94:    19 f4           brne    .+6      ; 0x9c <_ZN5DELAYC1EhRVh+0x30>
  96:    00 00           nop
  98:    00 00           nop
  9a:    00 00           nop
  9c:    2c 93           st    X, r18
  9e:    08 95           ret

000000a0 <main>:
  a0:    df 93           push    r29
  a2:    cf 93           push    r28
  a4:    00 d0           rcall    .+0      ; 0xa6 <main+0x6>
  a6:    00 d0           rcall    .+0      ; 0xa8 <main+0x8>
  a8:    00 d0           rcall    .+0      ; 0xaa <main+0xa>
  aa:    cd b7           in    r28, 0x3d; 61
  ac:    de b7           in    r29, 0x3e; 62
  ae:    ce 01           movw    r24, r28
  b0:    01 96           adiw    r24, 0x01; 1
  b2:    64 e0           ldi    r22, 0x04; 4
  b4:    4b e3           ldi    r20, 0x3B; 59
  b6:    50 e0           ldi    r21, 0x00; 0
  b8:    0e 94 36 00     call    0x6c; 0x6c <_ZN5DELAYC1EhRVh>
  bc:    ce 01           movw    r24, r28
  be:    04 96           adiw    r24, 0x04; 4
  c0:    65 e0           ldi    r22, 0x05; 5
  c2:    48 e3           ldi    r20, 0x38; 56
  c4:    50 e0           ldi    r21, 0x00; 0
  c6:    0e 94 36 00     call    0x6c; 0x6c <_ZN5DELAYC1EhRVh>
  ca:    ff cf           rjmp    .-2      ; 0xca <main+0x2a>

000000cc <__udivmodqi4>:
  cc:    99 1b           sub    r25, r25
  ce:    79 e0           ldi    r23, 0x09; 9
  d0:    04 c0           rjmp    .+8      ; 0xda <__udivmodqi4_ep>

000000d2 <__udivmodqi4_loop>:
  d2:    99 1f           adc    r25, r25
  d4:    96 17           cp    r25, r22
  d6:    08 f0           brcs    .+2      ; 0xda <__udivmodqi4_ep>
  d8:    96 1b           sub    r25, r22

000000da <__udivmodqi4_ep>:
  da:    88 1f           adc    r24, r24
  dc:    7a 95           dec    r23
  de:    c9 f7           brne    .-14     ; 0xd2 <__udivmodqi4_loop>
  e0:    80 95           com    r24
  e2:    08 95           ret
...

наблюдаем генерацию кода, вычисляющего константное выражение(==делающего работу препроцессора), а также обращение к регистру ввода-вывода посредством косвенной адресации, а не спец-команд.
Второе, помимо неоправданного увеличения размера кода, приводит к ошибкам компиляции, если в ассемблерных вставках использовать результаты вычисления подобных константных выражений.
Но, если в исходном коде закомментировать объявление одного из объектов класса DELAY, или один из if() в конструкторе класса DELAY, то генерится вполне нормальный код:
Код
#include <avr/io.h>
class DELAY{
    public:
    const uint8_t Cadd;
    volatile uint8_t& port;
    DELAY(const uint8_t c, volatile uint8_t& p):Cadd(c), port(p)
    {
    //    if ((Cadd%3)==0) asm volatile ("nop\n\t");
        if ((Cadd%3)==1) asm volatile ("nop\n\t" "nop\n\t");
        if ((Cadd%3)==2) asm volatile ("nop\n\t" "nop\n\t" "nop\n\t");
        port=c;
    }
};
int main(void)
{
    DELAY mod1(4,PORTA);
    DELAY mod2(5,PORTB);
    while(1);
    return 0;
}
-----------------------------------------------------------------------------------------
...
00000068 <__bad_interrupt>:
  68:    0c 94 00 00     jmp    0; 0x0 <__vectors>

0000006c <main>:
  6c:    00 00           nop
  6e:    00 00           nop
  70:    84 e0           ldi    r24, 0x04; 4
  72:    8b bb           out    0x1b, r24; 27
  74:    00 00           nop
  76:    00 00           nop
  78:    00 00           nop
  7a:    85 e0           ldi    r24, 0x05; 5
  7c:    88 bb           out    0x18, r24; 24
  7e:    ff cf           rjmp    .-2      ; 0x7e <main+0x12>

00000080 <_exit>:
  80:    f8 94           cli
...

Не пойму, что в первом варианте кода помешало все вычислить препроцессору? Ведь все константы известны изначально. И почему компилятор перестал использовать команды для работы с регистрами ввода-вывода IN,OUT и др.?


--------------------
- Бендер, ты же робот, зачем тебе пить пиво?
- Незачем! Я могу бросить в любой момент!
Go to the top of the page
 
+Quote Post
ReAl
сообщение Jul 25 2009, 12:50
Сообщение #2


Нечётный пользователь.
******

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



Во-первых, то, что Вы хотите - это работа не препроцессора.

Во-вторых - компилятор не обязан инлайнить конструктор, а для вызываемой функции это всё не константы, а переданные аргументы.
В данном случае попробуйте добавить
Код
    __attribute__((__always_inline__))
    DELAY(const uint8_t c, volatile uint8_t& p):Cadd(c), port(p)
    {
Поскольку данное указание приходится применять чаще, чем изредка, советую где-то в общем включаемом файле в духе gcc_macro.h добавить директиву (вот теперь уже препроцессора)
Код
#define INLINE   __attribute__((__always_inline__))
и дальше пользоваться им
Код
    INLINE  DELAY(const uint8_t c, volatile uint8_t& p):Cadd(c), port(p)



В третьих - посмотрите в сторону шаблонов (C++ template) - мне кажется, что в подобных случаях они лучше подходят.


--------------------
Ну, я пошёл… Если что – звоните…
Go to the top of the page
 
+Quote Post
injen-d
сообщение Jul 25 2009, 14:53
Сообщение #3


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

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



Цитата(ReAl @ Jul 25 2009, 16:50) *
Во-вторых - компилятор не обязан инлайнить конструктор

Вот что значит опыт!
Точно, проблема возникает из-за пропадания в какой-то момент желания инлайнить у компилятора. Черт, а я уже 2 дня перебираю варианты и не догадалсяcrying.gif наверное симптомы смутили,
ведь данная фишка компилятора(оптимизатора?) призвана уменьшить объем выходного кода, а тут наоборот - увеличение в 2-3 раза и генерация кода, вычисляющего константные выражения...
Спасибо!


--------------------
- Бендер, ты же робот, зачем тебе пить пиво?
- Незачем! Я могу бросить в любой момент!
Go to the top of the page
 
+Quote Post

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

 


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


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