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

 
 
 
Reply to this topicStart new topic
> Проблема с inline в EWAVR, Оптимизация Function inlining режет код
Makki
сообщение Sep 24 2013, 17:45
Сообщение #1


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



Такая ситуация: имеем несколько вложенных друг в друга функций: main( level1 (level2 ())), полная оптимизация по скорости.
При компиляции код функций уровня вложенности больше 2 просто исчезает (в дизассемблере смотрел), хоть просто возвращай переменную, хоть что угодно.
Выполняется main( level1 ()) без вызова level2 ()
Убил часа 4 на поиск причины. Пока не добрался до function inlining.
Отключил function inlining, все остальное так и оставил - помогло.

Кто-нибудь знает, что это такое было???

И таки да, у меня Kickstart на 4 кб.
Go to the top of the page
 
+Quote Post
Сергей Борщ
сообщение Sep 24 2013, 21:27
Сообщение #2


Гуру
******

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



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


--------------------
На любой вопрос даю любой ответ
"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
Makki
сообщение Sep 25 2013, 11:54
Сообщение #3


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



В общем-то вызываемая функция возвращает разные заначения, сейчас покажу. Так что думаю, не то это.
Исходник:

CODE

//Функция проверки кадра
//Возвращает 0 если все ОК
//#pragma inline=forced
unsigned char modbus_frame_check(void)
{
//Ошибки физического уровня (в usart0_received)
if((usart_flags&(1<<mberr))!=0){return 1;}
//Длина кадра (не менее 4 символов)
unsigned char num=usart_count;
if(num<4){return 2;}
//Контрольная сумма
num-=2;
//if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;}
//
return num;
}

/************************************************************/
//Обработчик ведомого Modbus (зациклен)
void modbus_slave_routine(void)
{
start:
//Сбрасываем таймер и всё-всё-всё и ждем приема
ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok));
TCNT1H=0;
TCNT1L=0;
TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
usart_count=0;
usart_SP=&usart_stack[0];
//Ждем первый символ
while((usart_flags&(1<<rxok))==0){;}
//Ждем окончания приема кадра
while((usart_flags&(1<<t15))==0){;}
//Проверяем посылку
if(modbus_frame_check()!=0){goto start;}
//Обрабатываем посылку и готовим ответ
_delay_ms(20);

}


И то, что в дизассемблере с включенной Function inlining:

CODE
@00000096: modbus_slave_routine
276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok));
+00000096: B100 IN R16,0x00 In from I/O location
+00000097: 700F ANDI R16,0x0F Logical AND with immediate
+00000098: B900 OUT 0x00,R16 Out to I/O location
277: TCNT1H=0;
+00000099: E000 LDI R16,0x00 Load immediate
+0000009A: BD0D OUT 0x2D,R16 Out to I/O location
278: TCNT1L=0;
+0000009B: BD0C OUT 0x2C,R16 Out to I/O location
279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
+0000009C: E008 LDI R16,0x08 Load immediate
+0000009D: BD0E OUT 0x2E,R16 Out to I/O location
283: while((usart_flags&(1<<rxok))==0){;}
+0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set
+0000009F: CFFE RJMP PC-0x0001 Relative jump
285: while((usart_flags&(1<<t15))==0){;}
+000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set
+000000A1: CFFE RJMP PC-0x0001 Relative jump
287: if(modbus_frame_check()!=0){goto start;}
+000000A2: B100 IN R16,0x00 In from I/O location
+000000A3: CFF2 RJMP PC-0x000D Relative jump


Как видно, modbus_frame_check() вообще не вызывается. И что характерно, даже нет попытки ее компилировать (если я правильно выражаюсь) - ее просто нет.
А теперь отключаем оптимизацию Function inlining - функция появилась и работает:

CODE
@000000AF: modbus_frame_check
259: if((usart_flags&(1<<mberr))!=0){return 1;}
+000000AF: 9B03 SBIS 0x00,3 Skip if bit in I/O register set
+000000B0: C002 RJMP PC+0x0003 Relative jump
259: if((usart_flags&(1<<mberr))!=0){return 1;}
+000000B1: E001 LDI R16,0x01 Load immediate
+000000B2: 9508 RET Subroutine return
261: unsigned char num=usart_count;
+000000B3: 91000000 LDS R16,0x0000 Load direct from data space
262: if(num<4){return 2;}
+000000B5: 3004 CPI R16,0x04 Compare with immediate
+000000B6: F410 BRCC PC+0x03 Branch if carry cleared
262: if(num<4){return 2;}
+000000B7: E002 LDI R16,0x02 Load immediate
+000000B8: 9508 RET Subroutine return
267: return num;
+000000B9: 5002 SUBI R16,0x02 Subtract immediate
+000000BA: 9508 RET Subroutine return
@000000BB: modbus_slave_routine
272: void modbus_slave_routine(void)
273: {
+000000BB: E000 LDI R16,0x00 Load immediate
+000000BC: E012 LDI R17,0x02 Load immediate
+000000BD: 9300015A STS 0x015A,R16 Store direct to data space
+000000BF: 9310015B STS 0x015B,R17 Store direct to data space
276: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok));
+000000C1: B100 IN R16,0x00 In from I/O location
+000000C2: 700F ANDI R16,0x0F Logical AND with immediate
+000000C3: B900 OUT 0x00,R16 Out to I/O location
277: TCNT1H=0;
+000000C4: E000 LDI R16,0x00 Load immediate
+000000C5: BD0D OUT 0x2D,R16 Out to I/O location
278: TCNT1L=0;
+000000C6: BD0C OUT 0x2C,R16 Out to I/O location
279: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
+000000C7: E008 LDI R16,0x08 Load immediate
+000000C8: BD0E OUT 0x2E,R16 Out to I/O location
280: usart_count=0;
+000000C9: E000 LDI R16,0x00 Load immediate
+000000CA: 9300015E STS 0x015E,R16 Store direct to data space
283: while((usart_flags&(1<<rxok))==0){;}
+000000CC: 9B02 SBIS 0x00,2 Skip if bit in I/O register set
+000000CD: CFFE RJMP PC-0x0001 Relative jump
285: while((usart_flags&(1<<t15))==0){;}
+000000CE: 9B00 SBIS 0x00,0 Skip if bit in I/O register set
+000000CF: CFFE RJMP PC-0x0001 Relative jump
287: if(modbus_frame_check()!=0){goto start;}
+000000D0: DFDE RCALL PC-0x0021 Relative call subroutine
+000000D1: 2300 TST R16 Test for Zero or Minus
+000000D2: F771 BRNE PC-0x11 Branch if not equal
289: _delay_ms(20);
+000000D3: E30F LDI R16,0x3F Load immediate
+000000D4: E91C LDI R17,0x9C Load immediate
+000000D5: 5001 SUBI R16,0x01 Subtract immediate
+000000D6: 4010 SBCI R17,0x00 Subtract immediate with carry
+000000D7: F7E9 BRNE PC-0x02 Branch if not equal
+000000D8: C000 RJMP PC+0x0001 Relative jump
+000000D9: 0000 NOP No operation
291: }
+000000DA: 9508 RET Subroutine return


Что характерно, если из вызывающей функции удалить обнуление таймера и счетчиков, все тоже работает, только вызываемая функция заинлайнена:

CODE
@00000096: modbus_slave_routine
272: void modbus_slave_routine(void)
273: {
+00000096: 9110015E LDS R17,0x015E Load direct from data space
283: while((usart_flags&(1<<rxok))==0){;}
+00000098: 9B02 SBIS 0x00,2 Skip if bit in I/O register set
+00000099: CFFE RJMP PC-0x0001 Relative jump
285: while((usart_flags&(1<<t15))==0){;}
+0000009A: 9B00 SBIS 0x00,0 Skip if bit in I/O register set
+0000009B: CFFE RJMP PC-0x0001 Relative jump
287: if(modbus_frame_check()!=0){goto start;}
+0000009C: 9903 SBIC 0x00,3 Skip if bit in I/O register cleared
+0000009D: CFFA RJMP PC-0x0005 Relative jump
+0000009E: 2F01 MOV R16,R17 Copy register
+0000009F: 3014 CPI R17,0x04 Compare with immediate
+000000A0: F3B8 BRCS PC-0x08 Branch if carry set
+000000A1: 5002 SUBI R16,0x02 Subtract immediate
+000000A2: F7A9 BRNE PC-0x0A Branch if not equal
289: _delay_ms(20);
+000000A3: E30F LDI R16,0x3F Load immediate
+000000A4: E91C LDI R17,0x9C Load immediate
+000000A5: 5001 SUBI R16,0x01 Subtract immediate
+000000A6: 4010 SBCI R17,0x00 Subtract immediate with carry
+000000A7: F7E9 BRNE PC-0x02 Branch if not equal
+000000A8: C000 RJMP PC+0x0001 Relative jump
+000000A9: 0000 NOP No operation
291: }
+000000AA: 9508 RET Subroutine return


Вот это для меня уже вообще непостижимо.
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Sep 25 2013, 12:08
Сообщение #4


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



modbus_frame_check() в том виде, в котором он приведен в примере, не может вернуть 0 ни при каких условиях. Вызов исключен законно.
Go to the top of the page
 
+Quote Post
Makki
сообщение Sep 25 2013, 12:20
Сообщение #5


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



Естественно об этом я тоже думал. Вот такой код:

CODE

//Функция проверки кадра
//Возвращает 0 если все ОК
//#pragma inline=forced
unsigned char modbus_frame_check(void)
{
//Ошибки физического уровня (в usart0_received)
if((usart_flags&(1<<mberr))!=0){return 1;}
//Длина кадра (не менее 4 символов)
unsigned char num=usart_count;
if(num<4){return 2;}
//Контрольная сумма
num-=2;
//if(crc16(&usart_stack[0],num)!=(usart_stack[num]+(usart_stack[num+1]<<8))){return 3;}
//
return 0;//num;
}


Генерит то же самое:

CODE
@00000096: modbus_slave_routine
285: ClearBits(usart_flags,(1<<t15)|(1<<t35)|(1<<mberr)|(1<<rxok));
+00000096: B100 IN R16,0x00 In from I/O location
+00000097: 700F ANDI R16,0x0F Logical AND with immediate
+00000098: B900 OUT 0x00,R16 Out to I/O location
286: TCNT1H=0;
+00000099: E000 LDI R16,0x00 Load immediate
+0000009A: BD0D OUT 0x2D,R16 Out to I/O location
287: TCNT1L=0;
+0000009B: BD0C OUT 0x2C,R16 Out to I/O location
288: TCCR1B=(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10);
+0000009C: E008 LDI R16,0x08 Load immediate
+0000009D: BD0E OUT 0x2E,R16 Out to I/O location
292: while((usart_flags&(1<<rxok))==0){;}
+0000009E: 9B02 SBIS 0x00,2 Skip if bit in I/O register set
+0000009F: CFFE RJMP PC-0x0001 Relative jump
294: while((usart_flags&(1<<t15))==0){;}
+000000A0: 9B00 SBIS 0x00,0 Skip if bit in I/O register set
+000000A1: CFFE RJMP PC-0x0001 Relative jump
296: if(modbus_frame_check()!=0){goto start;}
+000000A2: B100 IN R16,0x00 In from I/O location
+000000A3: CFF2 RJMP PC-0x000D Relative jump
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Sep 25 2013, 12:23
Сообщение #6


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



А как объявлен usart_count?
Go to the top of the page
 
+Quote Post
Makki
сообщение Sep 25 2013, 12:39
Сообщение #7


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



Как глобальная переменная (это видно по коду modbus_slave_routine()).
unsigned char usart_count=0;

А, я понял, к чему вы клоните.
Тогда, похоже, компилятор даже не предполагает, что в modbus_slave_routine() между
usart_count=0;
и
modbus_frame_check()
переменная usart_count может быть изменена прерыванием.

Но тогда при чем здесь Function inlining???
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Sep 25 2013, 13:08
Сообщение #8


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Makki @ Sep 25 2013, 16:39) *
Но тогда при чем здесь Function inlining???

Потому что после включения modbus_frame_check() в состав modbus_slave_routine() компилятор и обнаружил, что usart_count в modbus_frame_check() всегда равен нулю.
Go to the top of the page
 
+Quote Post
Makki
сообщение Sep 25 2013, 13:28
Сообщение #9


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



Всё, теперь мне все стало понятно. Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием...
Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно.

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

?
Go to the top of the page
 
+Quote Post
aaarrr
сообщение Sep 25 2013, 13:47
Сообщение #10


Гуру
******

Группа: Свой
Сообщений: 10 713
Регистрация: 11-12-04
Пользователь №: 1 448



Цитата(Makki @ Sep 25 2013, 17:28) *
Жалко, что компилятор даже не думает о том, что глобальная переменная может быть изменена прерыванием...
Не, погодите, а как тогда семафоры передавать? И ждать их изменения? Тут что-то не так все равно.

Об этом должен думать программист. Ключевое слово volatile.
Go to the top of the page
 
+Quote Post
Makki
сообщение Sep 25 2013, 14:05
Сообщение #11


Участник
*

Группа: Участник
Сообщений: 19
Регистрация: 8-10-07
Пользователь №: 31 163



Ага. Все понял, как только в раздел Type qualifiers заглянул. Спасибо за наводку! Пошел читать руководство...
Go to the top of the page
 
+Quote Post

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

 


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


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