|
Оптимизация кода IAR С++ v5.10 компилятора, весьма странный код... :( |
|
|
|
May 18 2008, 15:47
|

Любитель
    
Группа: Свой
Сообщений: 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? Почему бы не выполнять их один раз перед/после цикла? Не подскажете, уважаемые, каким образом образумить тупонький компилятор? А то запарил он повсюду создавать подобную конструкцию... ЗЫ: вспомнил, что по ИАРу есть отдельная ветка, если нужно, то пусть модераторы перекинут тему туда, извиняюсь...
|
|
|
|
|
May 18 2008, 17:33
|

Любитель
    
Группа: Свой
Сообщений: 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 компилятором. Ещё коммерческий, называется... Больше на любительскую поделку похоже  ЗЫ:А memcpy, похоже, не работает с флэш памятью.
|
|
|
|
|
May 18 2008, 17:51
|

Любитель
    
Группа: Свой
Сообщений: 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() - проблемы нет, лишние комманды исчезли... Попробую всю подпрограмму переместить в файл с main()... ...чёрт, если оформлять цикл внутри функции (подпрограммы), чтение (и даже запись) обхватываются командами MOVW... Как же этого избежать???
|
|
|
|
|
May 18 2008, 21:04
|

Гуру
     
Группа: Свой
Сообщений: 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
|
|
|
|
|
May 19 2008, 13:40
|

Любитель
    
Группа: Свой
Сообщений: 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, похоже, никуда не деться, так сказать, издержки компиляции Зато заметил, что при установке уровня оптимизации по скорости на средний - получаем наконец желаемое: Код 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 но тут уже другие участки кода становятся не идеальными... Интересно, можно ли как-то получить красивый код такого цикла при высоком уровне оптимизации?
|
|
|
|
|
May 19 2008, 14:04
|

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

|
Цитата ...попробовал вот так: из этого никак не могло Цитата ..но получилось тоже самое: Приведите Вашу функцию целиком Забыл - желательно так, чтобы ее можно было откомпилить.
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 19 2008, 14:11
|

Любитель
    
Группа: Свой
Сообщений: 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...
|
|
|
|
|
May 19 2008, 15:03
|

Профессионал
    
Группа: Модераторы
Сообщений: 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
|
|
|
|
|
May 19 2008, 15:10
|

Любитель
    
Группа: Свой
Сообщений: 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 никуда не уходят. Оптимизации, мать их так
|
|
|
|
|
May 19 2008, 15:55
|

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

|
Цитата(zltigo @ May 19 2008, 20:31)  Ну еще можете заняться индивидуальным террором - прагмами указывать разные ключи оптимизации для разных кусков текста. Да, порой приходится переставлять/расписывать операторы/операнды в случае особо коряво скомпилированного кода. Наверное, никак пока не привыкну к компиляторам после чисто ассемблерного программирования...  В данном случае проблема не велика, конечно, просто стало интересно, как на это смотрит остальное сообщество. Может быть, только у меня такая "шняга"?  ЗЫ: Вот зачем надо было вводить второй стёк для данных? В листинге не нашёл ни единой команды push/pop. Целый регистр-указатель под это угробили. А потом конечно, пихаем сначала r16:r17 в Z, юзаем его, затем пихаем в него r18:r19 и т.д, вместо естественной работы с двумя указателями... Ужас  Обработчики прерываний (в виде единой функции!) с длиннющим сохранением регистров на стёк, когда на асме обошёлся бы парой-тройкой... Порой больно смотреть на такое разбазаривание ресурсов проца...  Но начинаю привыкать к С, уже лень становится писать что-либо на асме...
|
|
|
|
|
May 19 2008, 16:29
|

Йа моск ;)
     
Группа: Модераторы
Сообщений: 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 лет назад
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 19 2008, 16:52
|

Любитель
    
Группа: Свой
Сообщений: 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 лет назад  Спасибо Дмитрий, попробую  Насчёт прерываний - в том то и дело, что каких-либо вызовов функций нет, а сохраняется по 7-9 регистров на CSTACK. Возможно, слишком громоздкий код получается, конечно. По стеку понятно, для большого кол-ва переменных это будет выгодно, наверное, хотя у себя я пока не наблюдал подгрузку данных с регистра Y... ЗЫ: Хочу передать Вам большой респект, как кодеру известной в своё время команды Codebusters До сих пор помню Satisfaction megademo, сколько раз тогда запускал её и любовался эффектами и музыкой... Приятно, что этот форум посещают подобные вам люди
|
|
|
|
|
May 19 2008, 18:05
|

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

|
Да, чудесным образом лишние инструкции исчезли! Как я понял, всё это путём небольшого изменения порядка следования команд, введения дополнительных указателей/или переменных для исключения лишних вычислений и парочкой прагм... Да-а, башку можно сломать от такого напряга В общем вот что получилось в итоге: Код 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". Магия?
|
|
|
|
|
May 19 2008, 18:36
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

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

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

|
Цитата Проблемы только с переносимостью между компиляторами делаем так - Код #ifndef __IAR_SYSTEMS_ICC__ #define __x #define __z #define __z_x #define __x_z #endif И нет проблемы  Цитата У Gcc с этим чуть по лучше Это пока стекового фрейма нет. Как только он появляется - все, гаплык.... Кстати, а не подскажете по-быстрому, как GCC заставить генерить асмовский листинг с исходным текстом на Си в каментах?
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 20 2008, 07:31
|
дятел
    
Группа: Свой
Сообщений: 1 681
Регистрация: 13-05-06
Из: Питер
Пользователь №: 17 065

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

Любитель
    
Группа: Свой
Сообщений: 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 И нет проблемы  Хм, непонятно, а где-же указание компилеру, какие действия выполнять при обнаружении подобного преффикса? Это что, зашито мёртво в любой компилер?
|
|
|
|
|
May 21 2008, 12:54
|
Местный
  
Группа: Свой
Сообщений: 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{//ïðèåì äàííûõ } } Знать-бы какие подсказки компилер понимает
|
|
|
|
|
May 21 2008, 13:06
|

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

|
Цитата 3 варианта одного и того-же Местные телепаты требуют полностью функцию  Желательно, с обрамлением, чтобы можно было собрать. А, просмотрелся... Вы уже асилили подсказать компилятору..
--------------------
"Практика выше (теоретического) познания, ибо она имеет не только достоинство всеобщности, но и непосредственной действительности." - В.И. Ленин
|
|
|
|
|
May 21 2008, 14:32
|

Гуру
     
Группа: Модераторы
Сообщений: 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)
|
|
|
|
|
May 26 2008, 17:12
|

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

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

Местный
  
Группа: Свой
Сообщений: 268
Регистрация: 4-11-05
Пользователь №: 10 470

|
Немного не в тему, потому как речь о версии ИАР 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) Присоединяю файл проекта если у кого не развита телепатия
|
|
|
|
|
Nov 28 2010, 06:37
|
Гуру
     
Группа: Свой
Сообщений: 2 702
Регистрация: 14-07-06
Пользователь №: 18 823

|
Цитата(Waso @ Nov 26 2010, 21:30)  Немного не в тему if((recbuf.byte[0] ==~recbuf.byte[1]) // это условие даже не проверяется Вы предупреждения компилятора вообще не читаете? Писатель?  Правая часть приводится к типу int. После инверсии в старшем байте казывается 0xff. Результат сравнения 0xXX и 0xFFYY компилятору ясен на этапе компиляции.
--------------------
Уходя, оставьте свет...
|
|
|
|
|
Nov 28 2010, 19:33
|

Местный
  
Группа: Свой
Сообщений: 268
Регистрация: 4-11-05
Пользователь №: 10 470

|
demiurg_spb, неа, не канает. Xenia, Dog Pawlowa, я фшоке! Это действительно работает!! У меня сорвало крышу! Господа и дамы! Прошу! Объясните мне ради Бога! С какого рожна Цитата Правая часть приводится к типу int. Это что, происходит всегда, когда я произвожу над операндом какую-либо операцию прямо в условии??? Где прописано что это так делается? Я понимаю, если бы один из операндов был int или я например прибавлял к нему число голое.. Но туут.. %[]
|
|
|
|
1 чел. читают эту тему (гостей: 1, скрытых пользователей: 0)
Пользователей: 0
|
|
|