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

 
 
3 страниц V   1 2 3 >  
Reply to this topicStart new topic
> Оптимизация кода IAR С++ v5.10 компилятора, весьма странный код... :(
sonycman
сообщение May 18 2008, 15:47
Сообщение #1


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Всем привет.
Не даёт покоя один момент в коде программы.
Вкратце - есть прога на С, которую компилирует 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
А то запарил он повсюду создавать подобную конструкцию...

ЗЫ: вспомнил, что по ИАРу есть отдельная ветка, если нужно, то пусть модераторы перекинут тему туда, извиняюсь...
Go to the top of the page
 
+Quote Post
Diz
сообщение May 18 2008, 15:58
Сообщение #2


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

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



Может, попробовать через стандартную memcpy ?
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 18 2008, 16:06
Сообщение #3


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(Diz @ May 18 2008, 20:58) *
Может, попробовать через стандартную memcpy ?

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

Небольшие кусочки данных было бы выгоднее кидать самому, через простой цикл, только без заморочек компилера...
Go to the top of the page
 
+Quote Post
SasaVitebsk
сообщение May 18 2008, 16:42
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 2 712
Регистрация: 28-11-05
Из: Беларусь, Витебск, Строителей 18-4-220
Пользователь №: 11 521



Похоже указатель *text объявлен как volatile.
Попробуйте объявить другой указатель такогоже типа и переприсвоить перед циклом.
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 18 2008, 17:33
Сообщение #5


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



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

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

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


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

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

ЗЫ:А memcpy, похоже, не работает с флэш памятью.
Go to the top of the page
 
+Quote Post
Diz
сообщение May 18 2008, 17:47
Сообщение #6


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

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



Если не ошибаюсь, в IAR для флеша есть memcpy_P.
Go to the top of the page
 
+Quote Post
vet
сообщение May 18 2008, 17:47
Сообщение #7


Знающий
****

Группа: Свой
Сообщений: 550
Регистрация: 16-06-04
Из: Казань
Пользователь №: 32



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


--------------------
Главная линия этого опуса ясна мне насквозь!
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 18 2008, 17:51
Сообщение #8


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(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...
Как же этого избежать???
Go to the top of the page
 
+Quote Post
zltigo
сообщение May 18 2008, 21:04
Сообщение #9


Гуру
******

Группа: Свой
Сообщений: 13 372
Регистрация: 27-11-04
Из: Riga, Latvia
Пользователь №: 1 244



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

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
IgorKossak
сообщение May 19 2008, 05:44
Сообщение #10


Шаман
******

Группа: Модераторы
Сообщений: 3 064
Регистрация: 30-06-04
Из: Киев, Украина
Пользователь №: 221



Если речь идёт конкретно об IAR и функция не может быть однозначно заменена библиотечной типа memcpy_P(), то посмотрите в сторону атрибутов __x, __x_z ... описанных в \avr\doc\iccavr.htm
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 19 2008, 13:40
Сообщение #11


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(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

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

Интересно, можно ли как-то получить красивый код такого цикла при высоком уровне оптимизации?
Go to the top of the page
 
+Quote Post
Rst7
сообщение May 19 2008, 14:04
Сообщение #12


Йа моск ;)
******

Группа: Модераторы
Сообщений: 4 345
Регистрация: 7-07-05
Из: Kharkiv-city
Пользователь №: 6 610



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

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


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

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


--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 19 2008, 14:11
Сообщение #13


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(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...
Go to the top of the page
 
+Quote Post
KRS
сообщение May 19 2008, 15:03
Сообщение #14


Профессионал
*****

Группа: Модераторы
Сообщений: 1 951
Регистрация: 27-08-04
Из: Санкт-Петербург
Пользователь №: 555



Цитата(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
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 19 2008, 15:10
Сообщение #15


Любитель
*****

Группа: Свой
Сообщений: 1 864
Регистрация: 20-08-06
Из: Тольятти
Пользователь №: 19 695



Цитата(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
Go to the top of the page
 
+Quote Post

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

 


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


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