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

Keil: оптимизация -O3 + -Ot ломает логику программы

Приветствую!

 

Keil 5.28.0.0, оптимизация -O3 и установлен чекбокс оптимизации по скорости -Ot.

Есть функция

#define RBTYPE      u8
#define RB_BUF_SIZE (64 + 1)


typedef struct
{
  volatile s32 rp, wp;
  RBTYPE buf[RB_BUF_SIZE];
}sRingBuf;


s32 rb_Read(sRingBuf *rb, RBTYPE buf[], s32 len)
{
  s32 rlen = rb_GetBusy(rb);
  if(rlen > len) rlen = len;
  len = rlen; s32 rp = rb->rp;
  for(; len-- > 0; rp &= (rp - RB_BUF_SIZE) >> 31)
    *buf++ = rb->buf[rp++];
  rb->rp = rp; return rlen;
}

 

На неоптимизирующей сборке все отлично.

На -O3 + -Ot получаю следующий выхлоп:

0x08001634 B430      PUSH     {r4-r5}
0x08001636 4605      MOV      r5,r0
   114:   s32 t = rb->wp; 
0x08001638 6840      LDR      r0,[r0,#0x04]
   115:   if((t -= rb->rp) < 0) 
0x0800163A 682B      LDR      r3,[r5,#0x00]
   115:   if((t -= rb->rp) < 0) 
0x0800163C 1AC0      SUBS     r0,r0,r3
    44: { 
    45:   s32 rlen = rb_GetBusy(rb); 
0x0800163E D500      BPL      0x08001642
0x08001640 3041      ADDS     r0,r0,#0x41
    46:   if(rlen > len) rlen = len; 
0x08001642 4290      CMP      r0,r2
0x08001644 DC11      BGT      0x0800166A
    47:   len = rlen; s32 rp = rb->rp; 
    48: #if (pwroftwo(RB_BUF_SIZE)) 
    49:   for(; len-- > 0; rp &= RB_BUF_SIZE - 1) 
    50: #else 
0x08001646 682C      LDR      r4,[r5,#0x00]
    51:   for(; len-- > 0; rp &= (rp - RB_BUF_SIZE) >> 31) 
    52: #endif 
0x08001648 2800      CMP      r0,#0x00
0x0800164A DD0B      BLE      0x08001664
0x0800164C 4603      MOV      r3,r0
    53:     *buf++ = rb->buf[rp++]; 
0x0800164E 192A      ADDS     r2,r5,r4
0x08001650 7A12      LDRB     r2,[r2,#0x08]
0x08001652 700A      STRB     r2,[r1,#0x00]
0x08001654 4622      MOV      r2,r4
0x08001656 3A41      SUBS     r2,r2,#0x41
0x08001658 17D2      ASRS     r2,r2,#31
0x0800165A 4022      ANDS     r2,r2,r4
0x0800165C 1C54      ADDS     r4,r2,#1
0x0800165E 1C49      ADDS     r1,r1,#1
0x08001660 1E5B      SUBS     r3,r3,#1
0x08001662 D1F4      BNE      0x0800164E
    54:   rb->rp = rp; 
    55:   return rlen; 
0x08001664 602C      STR      r4,[r5,#0x00]
    56: } 
    57:  
    58: s32 rb_Write(sRingBuf *rb, RBTYPE buf[], s32 len) 
0x08001666 BC30      POP      {r4-r5}
0x08001668 4770      BX       lr

 

Интересует сам цикл:

Цитата

0x0800164E 192A      ADDS     r2,r5,r4
0x08001650 7A12      LDRB     r2,[r2,#0x08]
0x08001652 700A      STRB     r2,[r1,#0x00]
0x08001654 4622      MOV      r2,r4
0x08001656 3A41      SUBS     r2,r2,#0x41
0x08001658 17D2      ASRS     r2,r2,#31
0x0800165A 4022      ANDS     r2,r2,r4
0x0800165C 1C54      ADDS     r4,r2,#1
0x0800165E 1C49      ADDS     r1,r1,#1
0x08001660 1E5B      SUBS     r3,r3,#1
0x08001662 D1F4      BNE      0x0800164E

 

Как так??? С какого лешего сначала выполняется rp &= (rp - RB_BUF_SIZE) >> 31, а лишь потом постиндексация rp при записи в buf?

Ведь после выражения *buf++ = rb->buf[rp++]; (согласно стандарту) есть точка следования, и все побочные действия вычислений уже произошли.

Лишь потом должна выполниться операция очистки по маске (третий аргумент цикла)...

Из-за этого косяка у меня неправильно обрабатывается кольцо на максимальной оптимизации.

 

Если сделать тупо

for(; len-- > 0; rp &= (rp - RB_BUF_SIZE) >> 31)
{
  *buf++ = rb->buf[rp];
  ++rp;
}

то все работает как положено.

 

если сделать rp как volatile, то все будет тоже как положено.

 

Что это? Глюк оптимизации или я дурак?

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


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

49 минут назад, Forger сказал:

А компилятор-то какой?

Компилятор armcc v5.06 update 6 (build 750).

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


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

3 minutes ago, Arlleex said:

Компилятор armcc v5.06 update 6 (build 750).

Он уже несколько лет не обновлялся, числится как legacy. Поэтому всякое возможно ;)

Переходите на v6

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


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

32 минуты назад, Forger сказал:

Он уже несколько лет не обновлялся, числится как legacy. Поэтому всякое возможно ;)

Переходите на v6

Эх... Долго я с ним (armcc) дружил:boredom:

На v6 все работает как положено, спасибо.

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


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

Обнаружил, что со сменой компилятора перестали работать переходы по функциям/определениям и т.д.

По нажатию "Go to definition" внизу слева пишется No information available for the selected symbol. Галка "Browse information" в настройках стоит.

Может, знает кто, в чем проблема?

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


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

1 час назад, ViKo сказал:

А как на -o1?

Что на -O1? Появляется надпись или нет? Или Вы про баг компайлера?

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


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

8 минут назад, Arlleex сказал:

Что на -O1? Появляется надпись или нет? Или Вы про баг компайлера?

Так про оптимизацию же. Может, на -o3 нечего показывать по причине отсутствия. 

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


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

2 минуты назад, ViKo сказал:

Так про оптимизацию же. Может, на -o3 нечего показывать по причине отсутствия. 

Да как банальный #define A 100 может выкидываться оптимизатором? И при чем тут он... К тому же я сейчас на -O0 вообще, поскольку отлаживаюсь.

То бишь не только переходы по функциям не работают, не работают вообще любый переходы по символам, будь то функции или defines, typedefs и т.д.

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


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

Keil рекомендует использовать -o1.
http://www.keil.com/appnotes/files/apnt_298.pdf

Вряд ли оно, но почитайте, вдруг поможет.

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


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

21 minutes ago, ViKo said:

Keil рекомендует использовать -o1.

В дебаге использую -o1, для отлаживаемых модулей иногда временно включаю -o0 (через свойства файла), порой приходится, компилятор дюже умный, режет очень много даже на -o1

В релизе выбира "balanced".

 

ps В обеих сборках рекомендую везде ставить галку "One ELF section per function", сильно сокращает код, убирая неиспользуемые функции их объектных файлов.

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


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

29 минут назад, ViKo сказал:

Keil рекомендует использовать -o1.
http://www.keil.com/appnotes/files/apnt_298.pdf

Вряд ли оно, но почитайте, вдруг поможет.

Дело в том, что оптимизация не влияет и влиять не может на навигацию по проекту, так как она, скорее всего, работает просто как file search.

А с этой красной надписью встречался и раньше, возможно именно поэтому забил на этот компилятор и работал с armcc...

 

10 минут назад, Forger сказал:

В дебаге использую -o1...

Я дебажу в -O0, релиз в -O3 + -Ot (либо просто -O3). Но в новом компиляторе появилась balanced, поэтому юзать буду ее.

 

12 минут назад, Forger сказал:

ps В обеих сборках рекомендую везде ставить галку "One ELF section per function", сильно сокращает код, убирая неиспользуемые функции их объектных файлов.

Всегда так и было, собственно:smile:

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


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

4 minutes ago, Arlleex said:

Я дебажу в -O0, релиз в -O3 + -Ot (либо просто -O3). Но в новом компиляторе появилась balanced, поэтому юзать буду ее.:smile:

Если проект жирный, то -o0 для всех файлов делает его очень объемным, долго зашивается,

поэтому только для отлаживаемых файлов временно отключают оптимизацию (ставлю -o0)

Ксатати -o1, 02 и -o3 и др уже мало отличаются, честно говоря, особой разницы по производительности (загрузка задач в %) тоже не заметил, равно как и по объему кода и озу.

Однако, -o0 делает код сильно жирным и тормозным, разница заметна. Удобно для отладки. Если и с такой оптимизацией производительности хватает, то на остальных оптимизациях и подавно хвататит ))

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


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

14 минут назад, Forger сказал:

Если и с такой оптимизацией производительности хватает, то на остальных оптимизациях и подавно хвататит ))

В 90% случаев я оптимизацию ставлю лишь для защиты от модернизации бинарника ПО третьими лицами, а не для скорости...

Бывало такое в практике. Конечно, лучшим решением в этом случае было и остается шифрование, но блин: для не сильно сложных проектов это излишество.

А любителям реверса и -O3 хватит, чтобы вдоволь наиграться и сесть в лужу. К тому же, как мне известно, прошивки попадают к несильно компетентным людям.

А клоноделов и любителей пошаманить что-то в прошивке мы вынуждаем отказаться от этой затеи ввиду элементарной смены ревизии СПО на взаимодействующих модулях всего комплекса.

Поэтому сегодня они стырили бинарь и он работает на другой железке, а завтра мы обновляем ПО и клоны отвалились.

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


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

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

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

Гость
Ответить в этой теме...

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

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

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

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

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

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