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

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


Гуру
******

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



Цитата(sonycman @ May 19 2008, 17:10) *
Оптимизации, мать их так sad.gif

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


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 19 2008, 15:55
Сообщение #17


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

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



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

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

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

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

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

Порой больно смотреть на такое разбазаривание ресурсов проца... sad.gif
Но начинаю привыкать к С, уже лень становится писать что-либо на асме...
Go to the top of the page
 
+Quote Post
Rst7
сообщение May 19 2008, 16:29
Сообщение #18


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

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



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


Ну попробуйте такой вариант -
Код
#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


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


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

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



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


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

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



Да, чудесным образом лишние инструкции исчезли! 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
Go to the top of the page
 
+Quote Post
zltigo
сообщение May 19 2008, 18:09
Сообщение #21


Гуру
******

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



Цитата(sonycman @ May 19 2008, 20:05) *
Да-а, башку можно сломать от такого напряга cool.gif

В общем-то не слишком и сложно, если подумать, то не сложнее писания врукопашную на ASM. Опыт и навыки естественно нужны. Проблемы только с переносимостью между компиляторами sad.gif


--------------------
Feci, quod potui, faciant meliora potentes
Go to the top of the page
 
+Quote Post
singlskv
сообщение May 19 2008, 18:36
Сообщение #22


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(Rst7 @ May 19 2008, 20:29) *
Тут много магии - отдельные указатели (почему-то иногда очень плохо у IAR'а по ходу выполнения функции переменные перемещаются по регистрам), no_cse... А в общем итоге видимо проблема заключается в том, что использование структур и двух указателей сразу приводит к нехватке регистровых пар. Видимо, тут GCC был бы на высоте.
О, это именно то о чем я твержу уже очень давно но все почему-то относятся к этому
скептически, IAR действительно дуреет когда количество источников/приемников данных
в близлежащем коде >2, причем обращение к структурам у него часто идет как обращение
к источнику/приемнику данных. При этом выбор того что будет адресоваться через регистровую
пару зависит от порядка обращения в исходнике. У Gcc с этим чуть по лучше, правда, если уж
совсем по-честному, иногда лишние movw тоже бывают, но лечится обычно просто заведением локальных указателей без всяких прагм.
Go to the top of the page
 
+Quote Post
Rst7
сообщение May 20 2008, 07:01
Сообщение #23


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

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



Цитата
Проблемы только с переносимостью между компиляторами


делаем так -

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


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

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


Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах?


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


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



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

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

avr-objdump -S proname.elf >progname.lst
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 20 2008, 11:58
Сообщение #25


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

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



Цитата(Rst7 @ May 20 2008, 11:01) *
делаем так -

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


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

Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса?
Это что, зашито мёртво в любой компилер?
Go to the top of the page
 
+Quote Post
singlskv
сообщение May 20 2008, 12:09
Сообщение #26


дятел
*****

Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065



Цитата(sonycman @ May 20 2008, 15:58) *
Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса?
Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить
пустое место.
Go to the top of the page
 
+Quote Post
sonycman
сообщение May 20 2008, 12:18
Сообщение #27


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

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



Цитата(singlskv @ May 20 2008, 16:09) *
Там как раз и написано что если компилятор неИАР то вместо __x, итд подставить
пустое место.

А, понятно, то есть просто выключаем эту фичу...
Go to the top of the page
 
+Quote Post
Andreas1
сообщение May 21 2008, 12:54
Сообщение #28


Местный
***

Группа: Свой
Сообщений: 446
Регистрация: 12-03-06
Из: Москва
Пользователь №: 15 142



Еще непонятки с оптимизацией, правда в 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
Go to the top of the page
 
+Quote Post
Rst7
сообщение May 21 2008, 13:06
Сообщение #29


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

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



Цитата
3 варианта одного и того-же


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

А, просмотрелся... Вы уже асилили подсказать компилятору..


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


Гуру
******

Группа: Модераторы
Сообщений: 8 455
Регистрация: 15-05-06
Из: Рига, Латвия
Пользователь №: 17 095



Цитата(Andreas1 @ May 21 2008, 15:54) *
P.S. Это пока только заготовка

А попробуйте что-то вроде
Код
  if(RSStatus==RS_RECCMD)
{
      memcpy(RSRecCmdBuffer, &RSRecCmdBuffer, 7);
      RSRecCmdBuffer[7] = b;
memcpy - intrinsic, компилятор может ее реализовать эффективнее, чем компилируя ваш цикл.


--------------------
На любой вопрос даю любой ответ
"Write code that is guaranteed to work, not code that doesn’t seem to break" (C++ FAQ)
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 Текстовая версия Сейчас: 18th July 2025 - 16:13
Рейтинг@Mail.ru


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