Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Оптимизация кода IAR С++ v5.10 компилятора
Форум разработчиков электроники ELECTRONIX.ru > Микроконтроллеры (MCs) > Cредства разработки для МК > IAR
sonycman
Всем привет.
Не даёт покоя один момент в коде программы.
Вкратце - есть прога на С, которую компилирует IAR C/C++ Compiler for AVR
5.10A/W32 (5.10.1.5).
Оптимизация на макс. скорость.
Вот фрагмент сгенерированного кода:

Код
159                  for (a = length; a>0; a--)
   \   00000028   2F01               MOV     R16, R17
    160                  {
    161                      *pBuffer++    =    *text++;
   \                     ??usartSendCommand_4:
   \   0000002A   01F9               MOVW    R31:R30, R19:R18
   \   0000002C   9115               LPM     R17, Z+
   \   0000002E   019F               MOVW    R19:R18, R31:R30
   \   00000030   931D               ST      X+, R17
    162                  }
   \   00000032   950A               DEC     R16
   \   00000034   F7D1               BRNE    ??usartSendCommand_4


Вот думаю, для чего надо выполнять каждую итерацию цикла команды MOVW?
Почему бы не выполнять их один раз перед/после цикла?
Не подскажете, уважаемые, каким образом образумить тупонький компилятор? 07.gif
А то запарил он повсюду создавать подобную конструкцию...

ЗЫ: вспомнил, что по ИАРу есть отдельная ветка, если нужно, то пусть модераторы перекинут тему туда, извиняюсь...
Diz
Может, попробовать через стандартную memcpy ?
sonycman
Цитата(Diz @ May 18 2008, 20:58) *
Может, попробовать через стандартную memcpy ?

А через неё можно обращаться к флэш?

Небольшие кусочки данных было бы выгоднее кидать самому, через простой цикл, только без заморочек компилера...
SasaVitebsk
Похоже указатель *text объявлен как volatile.
Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом.
sonycman
Цитата(SasaVitebsk @ May 18 2008, 21:42) *
Похоже указатель *text объявлен как volatile.
Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом.

Нет, не volatile.
Вот объявления:

Код
char const __flash*    text;
unsigned char *pBuffer;


Пробовал объявлять и просто как unsigned char *text, всё побоку...

Можно, конечно, написать цикл на асме, если это было-бы критично, но не понятен смысл такой примитивной вставки комманд MOVW компилятором. Ещё коммерческий, называется...
Больше на любительскую поделку похоже smile.gif

ЗЫ:А memcpy, похоже, не работает с флэш памятью.
Diz
Если не ошибаюсь, в IAR для флеша есть memcpy_P.
vet
с флэш работает memcpy_P().
её объявление содержится в progmem.h, как и для других flash-версий стандартных функций.
sonycman
Цитата(Diz @ May 18 2008, 22:47) *
Если не ошибаюсь, в IAR для флеша есть memcpy_P.

Цитата(vet @ May 18 2008, 22:47) *
с флэш работает memcpy_P().
её объявление содержится в progmem.h, как и для других flash-версий стандартных функций.

Спасибо!

Интересно, вписал подобный цикл чисто для проверки прямо в тело main() - проблемы нет, лишние комманды исчезли... 05.gif
Попробую всю подпрограмму переместить в файл с main()...

...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW...
Как же этого избежать???
zltigo
Цитата(sonycman @ May 18 2008, 19:51) *
...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW...

Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить:
#pragma inline=forced
IgorKossak
Если речь идёт конкретно об IAR и функция не может быть однозначно заменена библиотечной типа memcpy_P(), то посмотрите в сторону атрибутов __x, __x_z ... описанных в \avr\doc\iccavr.htm
sonycman
Цитата(zltigo @ May 19 2008, 02:04) *
Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить:
#pragma inline=forced

Так их и нет, этих мелких функций. Строчка с копированием находится внутри большой функции, инлайнить нечего...

Цитата(IgorKossak @ May 19 2008, 10:44) *
Если речь идёт конкретно об IAR и функция не может быть однозначно заменена библиотечной типа memcpy_P(), то посмотрите в сторону атрибутов __x, __x_z ... описанных в \avr\doc\iccavr.htm


...попробовал вот так:
Код
__x_z    void    copymem_P(fbyte __flash*    source, byte*    dest, byte len)
{
    while(len--)
    {
        *dest++    =    *source++;
    }
}

...но получилось тоже самое:
Код
     92                  copymem_P(text, pBuffer, length);
   \   00000022   2F01               MOV     R16, R17
   \   00000024   01DF               MOVW    R27:R26, R31:R30
   \   00000026   9614               ADIW    R27:R26, 4
   \                     ??usartSendCommand_4:
   \   00000028   950A               DEC     R16
   \   0000002A   01F9               MOVW    R31:R30, R19:R18
   \   0000002C   9115               LPM     R17, Z+
   \   0000002E   019F               MOVW    R19:R18, R31:R30
   \   00000030   931D               ST      X+, R17
   \   00000032   F7D1               BRNE    ??usartSendCommand_4


Эх, от этих MOVW, похоже, никуда не деться, так сказать, издержки компиляции wacko.gif

Зато заметил, что при установке уровня оптимизации по скорости на средний - получаем наконец желаемое:
Код
     94                  for (a = length; a>0; a--)
   \   00000024   2F08               MOV     R16, R24
   \   00000026   C003               RJMP    ??usartSendCommand_4
     95                  {
     96                      *pBuffer++    =    *text++;
   \                     ??usartSendCommand_5:
   \   00000028   9115               LPM     R17, Z+
   \   0000002A   931D               ST      X+, R17
     97                  }
   \   0000002C   950A               DEC     R16
   \                     ??usartSendCommand_4:
   \   0000002E   2300               TST     R16
   \   00000030   F7D9               BRNE    ??usartSendCommand_5

но тут уже другие участки кода становятся не идеальными...

Интересно, можно ли как-то получить красивый код такого цикла при высоком уровне оптимизации?
Rst7
Цитата
...попробовал вот так:

из этого никак не могло
Цитата
..но получилось тоже самое:


Приведите Вашу функцию целиком

Забыл - желательно так, чтобы ее можно было откомпилить.
sonycman
Цитата(Rst7 @ May 19 2008, 19:04) *
из этого никак не могло
Приведите Вашу функцию целиком

Забыл - желательно так, чтобы ее можно было откомпилить.


Почему же не могло? Инлайн функция...
Проект специально собрал простой, для теста, всего два файла:

main.h
Код
typedef    unsigned long    dword;
typedef    unsigned short    word;
typedef    unsigned char    byte;
typedef char const __flash fbyte;

#define    USART_TEXT    10
#define    FALSE    0
#define    TRUE    1
#define    BAUD(x)    (QUARTZ/(16UL*x)-1)
#define    RX_SEEK    0
#define    RX_RUNNING    1
#define    USART_PREFFIX    2
#define    USART_HEADER    (USART_PREFFIX + 2)
#define    USART_FRONTEND    (USART_HEADER + 1)
#define    USART_MAXDATALENGTH    (sizeof(comm_buffer) - USART_FRONTEND)
#define    USART_TEXT    10

static struct    usart_rx_status
{
    byte    counter:    8;
    byte    mode:    8;
    volatile bool data_available:    1;
    bool    frame_err:    1;
    bool    ovrun_err:    1;
    bool    parity_err:    1;
    bool    length_err:    1;
    bool    lock_err:    1;
}    statusRx;

static struct    usart_tx_status
{
    byte    pointer:    8;
    byte    queue:    8;
    byte    length:    8;
//    volatile    bool    tx_active:    1;
//    bool    frame_err:    1;
//    bool    ovrun_err:    1;
//    bool    parity_err:    1;
    bool    length_err:    1;
//    bool    lock_err:    1;
}    statusTx;

static    byte    rx_buffer[16];
static    byte    tx_buffer[32];
static    byte    comm_buffer[sizeof(tx_buffer)];

#pragma    inline    =    forced
__x_z    void    copymem_P(fbyte __flash*    source, byte*    dest, byte len);

byte    CalculateCRC(const byte    *arr, byte size);
bool usartSendCommand(byte command, const void* pointer = 0, byte length = 0);

и main.cpp
Код
#include <ioavr.h>
#include <inavr.h>
#include <iom88.h>
#include <pgmspace.h>
#include    "main.h"
#include    <string.h>


__x_z    void    copymem_P(fbyte __flash*    source, byte*    dest, byte len)
{
    while(len--)
    {
        *dest++    =    *source++;
    }
}

byte    CalculateCRC(const byte    *arr, byte size)
{
    byte    crc    =    0;
    byte    bits;
    while(size--)
    {
        bits    =    *arr++;
        for(byte    k=0; k<8; k++)
        {
            if ((bits ^ crc)&0x01)
            {
                crc    >>=    1;
                crc    ^=    0x8c;
            }
            else
            {
                crc    >>=    1;
            }
            bits    >>=    1;
        }
    }
    return crc;
}


bool    usartSendData(const byte    *buffer, byte    length)
{
    byte    a, len;
    byte    *pBuffer;
    if (length > sizeof(tx_buffer) || length == 0)
    {
        statusTx.length_err    =    TRUE;
        return FALSE;
    }
    while (statusTx.length);
//    memcpy(tx_buffer, buffer, length);
    while    ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length);
    len    =    length;
    a = sizeof(tx_buffer) - statusTx.pointer;
    if (length > a)
    {
        len -= a;
        pBuffer    =    tx_buffer + statusTx.pointer;
        for (;a > 0;a--) *pBuffer++ = *buffer++;
        statusTx.pointer    =    0;
    }
    pBuffer    =    tx_buffer + statusTx.pointer;
    statusTx.pointer    +=    len;
    for (;len > 0;len--) *pBuffer++ = *buffer++;
    statusTx.length    =    length;
    UCSR0B    |=    1 << UDRIE0;
    statusTx.length_err    =    FALSE;
    return    TRUE;
}
    
bool    usartSendString(fbyte __flash    *pointer)
{
    return usartSendCommand(USART_TEXT, (const void*)pointer, strlen_P(pointer));
}

bool    usartSendCommand(byte command, const void* pointer, byte length)
{
    byte    a;
    byte    *pBuffer;

    switch (command)
    {
    case    USART_TEXT:
        if (!length || length > USART_MAXDATALENGTH) return FALSE;
        fbyte    __flash*    text;
        text    =    (fbyte __flash*)pointer;
        pBuffer    =    comm_buffer + USART_PREFFIX;
        *pBuffer++    =    command;
        *pBuffer++    =    length;

//        copymem_P(text, pBuffer, length);
        
        for (a = length; a>0; a--)
        {
            *pBuffer++    =    *text++;
        }
        
        *pBuffer    =    CalculateCRC(pBuffer    -    length, length);
        break;
    default:
        return    FALSE;
    }
    pBuffer    =    comm_buffer;
    *pBuffer++    =    'S';
    *pBuffer    =    'N';
    return usartSendData(comm_buffer, length + USART_FRONTEND);
}

int main()
{
    usartSendString("some text");
    
  return 0;
}


Проц - мега88, опции проекта:
--string_literals_in_flash
и установить галочку Enable bit definitions in include files...
KRS
Цитата(sonycman @ May 19 2008, 17:40) *
...попробовал вот так:
Код
__x_z    void    copymem_P(fbyte __flash*    source, byte*    dest, byte len)
{
    while(len--)
    {
        *dest++    =    *source++;
    }
}

так в данном случае надо __z_x или поменять местами указатели на флеш и память!
потому что у вас получается указатель на флеш в X, а он должен быть в Z
sonycman
Цитата(KRS @ May 19 2008, 20:03) *
так в данном случае надо __z_x или поменять местами указатели на флеш и память!
потому что у вас получается указатель на флеш в X, а он должен быть в Z


Поменял местами. Толку всё равно нет:
Код
  \                     ??usartSendCommand_4:
   \   00000028   950A               DEC     R16
   \   0000002A   01F9               MOVW    R31:R30, R19:R18
   \   0000002C   9115               LPM     R17, Z+
   \   0000002E   019F               MOVW    R19:R18, R31:R30
   \   00000030   931D               ST      X+, R17
   \   00000032   F7D1               BRNE    ??usartSendCommand_4


Вообще эта инлайн функция была приведена чисто для проверки, а так она там и даром не нужна.
Как видно, конечный код в случае использования функции практически не отличается от цикла вида: *pBuffer++ = *text++;
И MOVW никуда не уходят.
Оптимизации, мать их так sad.gif
zltigo
Цитата(sonycman @ May 19 2008, 17:10) *
Оптимизации, мать их так sad.gif

Ну еще можете заняться индивидуальным террором - прагмами указывать разные ключи оптимизации для разных кусков текста.
sonycman
Цитата(zltigo @ May 19 2008, 20:31) *
Ну еще можете заняться индивидуальным террором - прагмами указывать разные ключи оптимизации для разных кусков текста.

Да, порой приходится переставлять/расписывать операторы/операнды в случае особо коряво скомпилированного кода.
Наверное, никак пока не привыкну к компиляторам после чисто ассемблерного программирования... sad.gif

В данном случае проблема не велика, конечно, просто стало интересно, как на это смотрит остальное сообщество.
Может быть, только у меня такая "шняга"? smile.gif

ЗЫ: Вот зачем надо было вводить второй стёк для данных? В листинге не нашёл ни единой команды push/pop. Целый регистр-указатель под это угробили. А потом конечно, пихаем сначала r16:r17 в Z, юзаем его, затем пихаем в него r18:r19 и т.д, вместо естественной работы с двумя указателями...
Ужас sad.gif

Обработчики прерываний (в виде единой функции!) с длиннющим сохранением регистров на стёк, когда на асме обошёлся бы парой-тройкой...

Порой больно смотреть на такое разбазаривание ресурсов проца... sad.gif
Но начинаю привыкать к С, уже лень становится писать что-либо на асме...
Rst7
Цитата
Оптимизации, мать их так


Ну попробуйте такой вариант -
Код
#pragma optimize=no_cse
__x bool    usartSendData(const byte    *buffer, byte    length)
{
  byte    a, len;
  if (length > sizeof(tx_buffer) || length == 0)
  {
    statusTx.length_err    =    TRUE;
    return FALSE;
  }
  while (statusTx.length);
  while    ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length);
  len    =    length;
  a = sizeof(tx_buffer) - statusTx.pointer;
  if (length > a)
  {
    byte *p=tx_buffer + statusTx.pointer;
    len -= a;
    for (;a > 0;a--) *p++ = *buffer++;
    statusTx.pointer    =    0;
  }
  statusTx.pointer    +=    len;
  {
    byte *p=tx_buffer + statusTx.pointer;;
    for (;len > 0;len--) *p++ = *buffer++;
  }
  statusTx.length    =    length;
  UCSR0B    |=    1 << UDRIE0;
  statusTx.length_err    =    FALSE;
  return    TRUE;
}

bool    usartSendString(fbyte __flash    *pointer)
{
    return usartSendCommand(USART_TEXT, (const void*)pointer, strlen_P(pointer));
}


#pragma optimize=no_cse
__z bool    usartSendCommand(byte command, const void* pointer, byte length)
{
    byte    a;
    byte    *pBuffer;


    switch (command)
    {
    case    USART_TEXT:
        if (!length || length > USART_MAXDATALENGTH) return FALSE;
        pBuffer    =    comm_buffer + USART_PREFFIX;
        *pBuffer++    =    command;
        *pBuffer++    =    length;

//        copymem_P(pBuffer, (fbyte __flash *)pointer,  length);
    a=length;
    {
      byte *p=pBuffer;
      fbyte    __flash*    text;
      text    =    (fbyte __flash*)pointer;
      do
      {
            *p++    =    *text++;
      }
      while(--a);
      *p=CalculateCRC(pBuffer, length);
    }
        break;
    default:
        return    FALSE;
    }
    pBuffer    =    comm_buffer;
    *pBuffer++    =    'S';
    *pBuffer    =    'N';
    return usartSendData(comm_buffer, length + USART_FRONTEND);
}


Тут много магии - отдельные указатели (почему-то иногда очень плохо у IAR'а по ходу выполнения функции переменные перемещаются по регистрам), no_cse... А в общем итоге видимо проблема заключается в том, что использование структур и двух указателей сразу приводит к нехватке регистровых пар. Видимо, тут GCC был бы на высоте.

Цитата
Обработчики прерываний (в виде единой функции!) с длиннющим сохранением регистров на стёк, когда на асме обошёлся бы парой-тройкой...


Если какие-то функции другие вызываются - будет сохранение всех scratch-регистров, если нет - все будет хорошо.

Цитата
Вот зачем надо было вводить второй стёк для данных?


Вот GCC не делает второй стек для данных. Все хорошо, пока переменные одной функции помещаются в регистрах. Как только надо исполнить стековую переменную - начинается мрак, там такой код для пролога/эпилога, что с непривычки за голову хватаешься...

Тут конечно, надо бы было сделать 2 комманды при разработке ядра, LDD r,SP+disp и STD SP+disp,r и пару комманд увеличения/уменьшения указателя стека - и тогда бы здорово помогло... Но поезд ушел 10 лет назад smile.gif
sonycman
Цитата(Rst7 @ May 19 2008, 21:29) *
Ну попробуйте такой вариант
...
Если какие-то функции другие вызываются - будет сохранение всех scratch-регистров, если нет - все будет хорошо.
...
Вот GCC не делает второй стек для данных. Все хорошо, пока переменные одной функции помещаются в регистрах. Как только надо исполнить стековую переменную - начинается мрак, там такой код для пролога/эпилога, что с непривычки за голову хватаешься...

Тут конечно, надо бы было сделать 2 комманды при разработке ядра, LDD r,SP+disp и STD SP+disp,r и пару комманд увеличения/уменьшения указателя стека - и тогда бы здорово помогло... Но поезд ушел 10 лет назад smile.gif


Спасибо Дмитрий, попробую smile.gif

Насчёт прерываний - в том то и дело, что каких-либо вызовов функций нет, а сохраняется по 7-9 регистров на CSTACK. Возможно, слишком громоздкий код получается, конечно.

По стеку понятно, для большого кол-ва переменных это будет выгодно, наверное, хотя у себя я пока не наблюдал подгрузку данных с регистра Y...

ЗЫ: Хочу передать Вам большой респект, как кодеру известной в своё время команды Codebusters smile.gif
До сих пор помню Satisfaction megademo, сколько раз тогда запускал её и любовался эффектами и музыкой...
Приятно, что этот форум посещают подобные вам люди smile.gif
sonycman
Да, чудесным образом лишние инструкции исчезли! a14.gif
Как я понял, всё это путём небольшого изменения порядка следования команд, введения дополнительных указателей/или переменных для исключения лишних вычислений и парочкой прагм...

Да-а, башку можно сломать от такого напряга cool.gif

В общем вот что получилось в итоге:
Код
bool    usartSendData(const byte    *buffer, byte    length)
{
    byte    a, len;
    if (length > sizeof(tx_buffer) || length == 0)
    {
        statusTx.length_err    =    TRUE;
        return FALSE;
    }
    while (statusTx.length);
    while    ((byte)(sizeof(tx_buffer) - (byte)statusTx.queue) < length);
    len    =    length;
    a = sizeof(tx_buffer) - statusTx.pointer;
    if (length > a)
    {
        byte *p=tx_buffer + statusTx.pointer;
        len -= a;
        for (;a > 0;a--) *p++ = *buffer++;
        statusTx.pointer    =    0;
    }
    a    =    len;
    byte *p=tx_buffer + statusTx.pointer;
    for (;a > 0;a--) *p++ = *buffer++;
      statusTx.pointer    +=    len;
    statusTx.length    =    length;
    UCSR0B    |=    1 << UDRIE0;
    statusTx.length_err    =    FALSE;
    return    TRUE;
}

#pragma optimize=no_cse
__z    bool    usartSendCommand(byte command, const void* pointer, byte length)
{
    byte    a;
    byte    *pBuffer;
    
    switch (command)
    {
    case    USART_TEXT:
        if (!length || length > USART_MAXDATALENGTH) return FALSE;
        pBuffer    =    comm_buffer + USART_PREFFIX;
        *pBuffer++    =    command;
        *pBuffer++    =    length;
        a=length;
        byte *p;
        p    =    pBuffer;
        fbyte    __flash*    text;
      text    =    (fbyte __flash*)pointer;
      while(a--) *p++    =    *text++;
      *p = CalculateCRC(pBuffer, length);
        break;
    default:
        return    FALSE;
    }
    pBuffer    =    comm_buffer;
    *pBuffer++    =    'S';
    *pBuffer    =    'N';
    return usartSendData(comm_buffer, length + USART_FRONTEND);
}

Все три цикла копирования стали просто идеальными!
Причём первая функция сохраняет "стройность" и без "прагмы" и "__x".
Магия? rolleyes.gif
zltigo
Цитата(sonycman @ May 19 2008, 20:05) *
Да-а, башку можно сломать от такого напряга cool.gif

В общем-то не слишком и сложно, если подумать, то не сложнее писания врукопашную на ASM. Опыт и навыки естественно нужны. Проблемы только с переносимостью между компиляторами sad.gif
singlskv
Цитата(Rst7 @ May 19 2008, 20:29) *
Тут много магии - отдельные указатели (почему-то иногда очень плохо у IAR'а по ходу выполнения функции переменные перемещаются по регистрам), no_cse... А в общем итоге видимо проблема заключается в том, что использование структур и двух указателей сразу приводит к нехватке регистровых пар. Видимо, тут GCC был бы на высоте.
О, это именно то о чем я твержу уже очень давно но все почему-то относятся к этому
скептически, IAR действительно дуреет когда количество источников/приемников данных
в близлежащем коде >2, причем обращение к структурам у него часто идет как обращение
к источнику/приемнику данных. При этом выбор того что будет адресоваться через регистровую
пару зависит от порядка обращения в исходнике. У Gcc с этим чуть по лучше, правда, если уж
совсем по-честному, иногда лишние movw тоже бывают, но лечится обычно просто заведением локальных указателей без всяких прагм.
Rst7
Цитата
Проблемы только с переносимостью между компиляторами


делаем так -

Код
#ifndef __IAR_SYSTEMS_ICC__
#define __x
#define __z
#define __z_x
#define __x_z
#endif


И нет проблемы wink.gif

Цитата
У Gcc с этим чуть по лучше


Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах?
singlskv
Цитата(Rst7 @ May 20 2008, 11:01) *
Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах?
Это да, стараюсь до стекового фрейма не доводить...

если нужен листинг не для сборки а для посмотреть:

avr-objdump -S proname.elf >progname.lst
sonycman
Цитата(Rst7 @ May 20 2008, 11:01) *
делаем так -

Код
#ifndef __IAR_SYSTEMS_ICC__
#define __x
#define __z
#define __z_x
#define __x_z
#endif


И нет проблемы wink.gif

Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса?
Это что, зашито мёртво в любой компилер?
singlskv
Цитата(sonycman @ May 20 2008, 15:58) *
Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса?
Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить
пустое место.
sonycman
Цитата(singlskv @ May 20 2008, 16:09) *
Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить
пустое место.

А, понятно, то есть просто выключаем эту фичу...
Andreas1
Еще непонятки с оптимизацией, правда в IAR AVR 4.30
3 варианта одного и того-же
Код
     54              *ptr=b;
   \   00000026   8310               ST      Z, R17
     55              ptr-=7;
     56              if(*(ptr++)!=0xE0) return;//ptr++;
   \   00000028   9737               SBIW    R31:R30, 7
   \   0000002A   01DF               MOVW    R27:R26, R31:R30
   \   0000002C   9631               ADIW    R31:R30, 1
   \   0000002E   910C               LD      R16, X
   \   00000030   3E00               CPI     R16, 224
   \   00000032   F459               BRNE    ??RSRecByte_0
     57              if(*(ptr++)!=0x00) return;//ptr++;
   \   00000034   9101               LD      R16, Z+
   \   00000036   2300               TST     R16
   \   00000038   F441               BRNE    ??RSRecByte_0

Код
     54              *ptr=b;
   \   00000022   8310               ST      Z, R17
     55          //    ptr-=7;
     56              if(*(ptr++)!=0xE0) return;//ptr++;
   \   00000024   9101               LD      R16, Z+
   \   00000026   3E00               CPI     R16, 224
   \   00000028   F459               BRNE    ??RSRecByte_0
     57              if(*(ptr++)!=0x00) return;//ptr++;
   \   0000002A   9101               LD      R16, Z+
   \   0000002C   2300               TST     R16
   \   0000002E   F441               BRNE    ??RSRecByte_0

Код
     54              *ptr=b;
   \   00000022   8310               ST      Z, R17
     55              ptr-=7;
   \   00000024   9737               SBIW    R31:R30, 7
     56              if(*(ptr)!=0xE0) return;ptr++;
   \   00000026   9101               LD      R16, Z+
   \   00000028   3E00               CPI     R16, 224
   \   0000002A   F471               BRNE    ??RSRecByte_0
     57              if(*(ptr)!=0x00) return;ptr++;
   \   0000002C   9101               LD      R16, Z+
   \   0000002E   2300               TST     R16
   \   00000030   F459               BRNE    ??RSRecByte_0

Кроме того появляется сохранение/восстановление R26:27.
Вроде немного, но совершенно непонятная разница.
Получается, лучше дробить длинные выражения по кускам?
Цитата(zltigo @ May 19 2008, 22:09) *
В общем-то не слишком и сложно, если подумать, то не сложнее писания врукопашную на ASM. Опыт и навыки естественно нужны.

К сожалению, опыт приходится наживать свой и только мало-мало чужого, в отличие от писюкового программизма. Нет литературы, ориентированной на оптимальное написание на С.

P.S. Это пока только заготовка
Код
void RSRecByte(){
  if(!IsRecByteRS())return;
  byte b=GetByteRS();
  if(RSStatus==RS_RECCMD){//ïðèåì êîìàíäû
    byte *ptr=RSRecCmdBuffer; for(byte i=0;i<7;i++,ptr++)*ptr=*(ptr+1);
    *ptr=b;
    ptr-=7;
    if(*ptr!=0xE0) return;ptr++;
    if(*ptr!=0x00) return;ptr++;
    if(*ptr!=SysNum) return;ptr++;
    if(*ptr!=0x01) return;ptr++;
    RSStatus=1;
  }else{//ïðèåì äàííûõ
  }
}

Знать-бы какие подсказки компилер понимает sad.gif
Rst7
Цитата
3 варианта одного и того-же


Местные телепаты требуют полностью функцию wink.gif Желательно, с обрамлением, чтобы можно было собрать.

А, просмотрелся... Вы уже асилили подсказать компилятору..
Сергей Борщ
Цитата(Andreas1 @ May 21 2008, 15:54) *
P.S. Это пока только заготовка

А попробуйте что-то вроде
Код
  if(RSStatus==RS_RECCMD)
{
      memcpy(RSRecCmdBuffer, &RSRecCmdBuffer, 7);
      RSRecCmdBuffer[7] = b;
memcpy - intrinsic, компилятор может ее реализовать эффективнее, чем компилируя ваш цикл.
sonycman
Цитата(Сергей Борщ @ May 21 2008, 19:32) *
А попробуйте что-то вроде
Код
  if(RSStatus==RS_RECCMD)
{
   memcpy(RSRecCmdBuffer, &RSRecCmdBuffer, 7);
   RSRecCmdBuffer[7] = b;
memcpy - intrinsic, компилятор может ее реализовать эффективнее, чем компилируя ваш цикл.


Дело в том, что memcpy использует в качестве счетчика регистровую пару, работа с которой при переброске маленьких блоков данных выглядит весьма неэффективной...
Waso
Немного не в тему, потому как речь о версии ИАР 4.3. Но опера та-же. Не понимаю, почему ИАР считает заранее известным условие с volatile переменными:
Код
volatile union {       // для доступа к одной ячейке памяти разными способами
        unsigned long all;          // для доступа ко всем 4-м байтам
        unsigned char byte[4];      // для побайтного доступа
    } recbuf;

#pragma vector=INT0_vect
__interrupt void ext_int0_isr(void)
{
...
          recbuf.all>>=1; // сдвиг буфера на 1 бит
      if(bit)recbuf.byte[3]|=0x80;  // добавили единичку, если это она
...
}

void  main(void)
{
__enable_interrupt();
while (1)
  {

  if((recbuf.byte[0] ==~recbuf.byte[1])    // это условие даже не проверяется
  &&(recbuf.byte[2]==~recbuf.byte[3]))   // правда ругается на неопределенный порядок доступа
        {
            //  чтото делаем  - этот код компилятор выкидывает даже на низких уровнях оптимизации
         }
  }
}

Если то условие заменить таким - то все работает:
Код
    tmp = ~recbuf.byte[1];
    if(recbuf.byte[0] == tmp)
     {
        tmp = ~recbuf.byte[3];
        if(recbuf.byte[2] == tmp)

Присоединяю файл проекта если у кого не развита телепатия wink.gif
demiurg_spb
А если так:
Код
union {       // для доступа к одной ячейке памяти разными способами
         volatile unsigned long all;          // для доступа ко всем 4-м байтам
         volatile unsigned char byte[4];      // для побайтного доступа
     } recbuf;
Dog Pawlowa
Цитата(Waso @ Nov 26 2010, 21:30) *
Немного не в тему
if((recbuf.byte[0] ==~recbuf.byte[1]) // это условие даже не проверяется

Вы предупреждения компилятора вообще не читаете?
Писатель? wink.gif

Правая часть приводится к типу int. После инверсии в старшем байте казывается 0xff.
Результат сравнения 0xXX и 0xFFYY компилятору ясен на этапе компиляции.
Xenia
Вот так напишите и будет вам щастье: smile.gif

Код
void  main(void)
{
__enable_interrupt();
while (1)
  {
    if((recbuf.byte[0] ==(unsigned char)~recbuf.byte[1])
      &&(recbuf.byte[2]==(unsigned char)~recbuf.byte[3]))
    {
        //  что-то делаем
    }
  }
}
Waso
demiurg_spb, неа, не канает.

Xenia, Dog Pawlowa, я фшоке! Это действительно работает!! У меня сорвало крышу! Господа и дамы! Прошу! Объясните мне ради Бога! С какого рожна
Цитата
Правая часть приводится к типу int.
Это что, происходит всегда, когда я произвожу над операндом какую-либо операцию прямо в условии??? Где прописано что это так делается? Я понимаю, если бы один из операндов был int или я например прибавлял к нему число голое.. Но туут.. %[]
rezident
Цитата(Waso @ Nov 29 2010, 00:33) *
Где прописано что это так делается?
В стандарте С99 вестимо.
Цитата("ISO/IEC 9899:1999 (E)")
6.5 Expressions
...
4 Some operators (the unary operator ~, and the binary operators <<, >>, &, ^, and |,
collectively described as bitwise operators) are required to have operands that have
integer type
. These operators return values that depend on the internal representations of
integers, and have implementation-defined and undefined aspects for signed types.
Сергей Борщ
QUOTE (rezident @ Nov 28 2010, 22:43) *
В стандарте С99 вестимо.
А также там (и в предыдущих версиях стандарта тоже) написано, что при любых арифметических действиях операнды размером меньше int (unsigned int) неявно приводятся к int (unsigned int), но потом оптимизатор может выкинуть действия не влияющие на результат. И все это называется integer promotion rules.
Waso
Спасибо. Каюсь. Грешен. Ненавижу читать стандарты...

Уже в который раз я удивляюсь - каким чудом работали мои предыдущие программы??...
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.