Перейти к содержанию
    

Оптимизация кода IAR С++ v5.10 компилятора

Всем привет.

Не даёт покоя один момент в коде программы.

Вкратце - есть прога на С, которую компилирует 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:

А то запарил он повсюду создавать подобную конструкцию...

 

ЗЫ: вспомнил, что по ИАРу есть отдельная ветка, если нужно, то пусть модераторы перекинут тему туда, извиняюсь...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Может, попробовать через стандартную memcpy ?

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

 

Небольшие кусочки данных было бы выгоднее кидать самому, через простой цикл, только без заморочек компилера...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже указатель *text объявлен как volatile.

Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Похоже указатель *text объявлен как volatile.

Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом.

Нет, не volatile.

Вот объявления:

 

char const __flash*    text;
unsigned char *pBuffer;

 

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

 

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

Больше на любительскую поделку похоже :)

 

ЗЫ:А memcpy, похоже, не работает с флэш памятью.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

с флэш работает memcpy_P().

её объявление содержится в progmem.h, как и для других flash-версий стандартных функций.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если не ошибаюсь, в IAR для флеша есть memcpy_P.

с флэш работает memcpy_P().

её объявление содержится в progmem.h, как и для других flash-версий стандартных функций.

Спасибо!

 

Интересно, вписал подобный цикл чисто для проверки прямо в тело main() - проблемы нет, лишние комманды исчезли... :05:

Попробую всю подпрограмму переместить в файл с main()...

 

...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW...

Как же этого избежать???

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW...

Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить:

#pragma inline=forced

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Не ограничивать простор для возможности компилятору пооптимизировать и не создавать мелких функций, ну а если надо для, например, читаемости, то есть возможность заинлайнить:

#pragma inline=forced

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

 

Если речь идёт конкретно об 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:

 

Зато заметил, что при установке уровня оптимизации по скорости на средний - получаем наконец желаемое:

     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

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...попробовал вот так:

из этого никак не могло

..но получилось тоже самое:

 

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

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

из этого никак не могло

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

 

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

 

Почему же не могло? Инлайн функция...

Проект специально собрал простой, для теста, всего два файла:

 

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...

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

...попробовал вот так:

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

так в данном случае надо __z_x или поменять местами указатели на флеш и память!

потому что у вас получается указатель на флеш в X, а он должен быть в Z

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

так в данном случае надо __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 никуда не уходят.

Оптимизации, мать их так :(

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
К сожалению, ваш контент содержит запрещённые слова. Пожалуйста, отредактируйте контент, чтобы удалить выделенные ниже слова.
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...