Jump to content
    

При максимальной оптимизации - ошибка

1 минуту назад, const сказал:

я прошу sv = (glb & (1 << 6))

а получаю sv = glb

Нет. Вы получаете вызов foo() c тем или иным аргументом в зависимости от значения бита 6 в glb или ее не вызов если бит 6 не изменился. Как компилятор это реализует - его личное дело. 

Да, я был не прав - компилятор в этом случае, действительно, ошибся. Но еще раз подчеркиваю - он не обязан был хранить в sv именно то значение, которое вы хотели. 

Share this post


Link to post
Share on other sites

6 minutes ago, Сергей Борщ said:

Нет. Вы получаете вызов foo() c тем или иным аргументом в зависимости от значения бита 6 в glb или ее не вызов если бит 6 не изменился. Как компилятор это реализует - его личное дело. 

Да, я был не прав - компилятор в этом случае, действительно, ошибся. Но еще раз подчеркиваю - он не обязан был хранить в sv именно то значение, которое вы хотели. 

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

При таком поведении компилятора, ф-ция foo  будет вызыватся всегда, пока glb != 0 && glb != (1 << 6).

И как писал выше, когда добавляю дополнительную (временную) переменую, все встает на свои места.

А более новий IAR ведет себя предсказуемо всегда.

Share this post


Link to post
Share on other sites

2 часа назад, const сказал:

@Arlleex

Программа корректна, а результат компиляции нет.

Ну нет так нет.

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

Результат работы программы при "high balanced" оптимизации и при "medium" будет разный. А значит компилятор неправ. Как бы он ни оптимизировал код, результат выполнения меняться не должен.

Может, я что-то упускаю, но почему он будет разным?

Share this post


Link to post
Share on other sites

Посмотрел историю IAR:

ICCARM History

Хватает ошибок разных, особенно на уровне оптимизации High.

Вот возможно разновидность моего случая (не утверждаю):

"In EWARM 6.50.4:
An indirect assignment could be optimized incorrectly if the right hand side expression was masked with a constant and the only use was in a test, comparing the value, possibly masked with the same constant as in the assignment or a constant with fewer bits set, to zero. For example:
p->foo = x & 0x02;
...
if (p->foo & 0x02)

This has been corrected.
[EW23796]"

 

Кроме перехода на более свежую версию, наверное, и оптимизацию буду ставить не више Medium (всегда ставил High Balanced или High Speed).

Share this post


Link to post
Share on other sites

13 часов назад, Arlleex сказал:

Может, я что-то упускаю, но почему он будет разным?

Так вы посмотрите сами на получившийся код и подумайте - как он будет работать? И сравните с логикой, описанной исходником. Видно же, что результирующий код не соответствует логике исходника.

15 часов назад, _pv сказал:

в "упрощённой" версии и glb и sv всегда равны 0, не понятно почему целиком всё не выкинул, а только присвоение "соптимизировал".

Где же это видно? Вы неправы. Видно, что есть некая внешняя функция foo(), а также видно что glb - глобальная. А значит может изменяться например внутри той же foo(). А значит - она не может быть "всегда равна 0". Поэтому "выкинуть всё" - нельзя ни в каком случае. Была бы glb объявлена со "static" - другое дело.

Share this post


Link to post
Share on other sites

12 часов назад, const сказал:

Кроме перехода на более свежую версию, наверное, и оптимизацию буду ставить не више Medium (всегда ставил High Balanced или High Speed).

И зря. В IAR-ах с v7.80.4 не замечено серьёзных багов. За исключением тех о которых писал выше:

15 часов назад, jcxz сказал:

но по-крайней мере если не используется FPU и некоторые intrinsinc-и, то в 7.80.4 багов не замечал

И почему именно "medium"? Если боитесь потенциальных багов, так они могут быть на любом уровне оптимизации или вообще без неё. Ведь если в вашей версии IAR был такой баг, то это не гарантирует, что все другие баги будут в том же самом месте. Потенциальный баг может быть где угодно. Теоретически может быть даже такой баг, который есть при полностью выкл. оптимизации, но исчезает на высоком уровне оптимизации.

Использование высоких уровней оптимизации полезно при отладке своего кода тем, что часто приводит к проявлению скрытых багов в коде, не проявляющихся при низких уровнях оптимизации. Почему чайники часто и выключают оптимизацию - ведь при выкл. их код "работает", а при вкл. высокой начинает глючить.  :unknw:

Share this post


Link to post
Share on other sites

CLang на максимальной оптимизации и LTO просто выкинул весь код. И правильно сделал.
 

Цитата

Видно, что есть некая внешняя функция foo(), а также видно что glb - глобальная. А значит может изменяться например внутри той же foo(). А значит - она не может быть "всегда равна 0". Поэтому "выкинуть всё" - нельзя ни в каком случае. Была бы glb объявлена со "static" - другое дело.

main() - точка входа в Си-программу, поэтому на момент входа все глобальные переменные без инициализации равны 0.

В описании IAR-овского компилятора написано, что при High balanced осуществляется анализ памяти. Может, так он и сделал?

Share this post


Link to post
Share on other sites

33 minutes ago, Arlleex said:

CLang на максимальной оптимизации и LTO просто выкинул весь код. И правильно сделал.
 

вынесите ф-цию foo в другой файл. Неужели и в таком случае выкинет.

4 hours ago, jcxz said:

И почему именно "medium"? Если боитесь потенциальных багов, так они могут быть на любом уровне оптимизации или вообще без неё. Ведь если в вашей версии IAR был такой баг, то это не гарантирует, что все другие баги будут в том же самом месте. Потенциальный баг может быть где угодно. Теоретически может быть даже такой баг, который есть при полностью выкл. оптимизации, но исчезает на высоком уровне оптимизации.

Использование высоких уровней оптимизации полезно при отладке своего кода тем, что часто приводит к проявлению скрытых багов в коде, не проявляющихся при низких уровнях оптимизации. Почему чайники часто и выключают оптимизацию - ведь при выкл. их код "работает", а при вкл. высокой начинает глючить.

Потому что по приведенной мной ссылке выражение "On optimization level High..." встречается довольно часто. Как я понял, большенство ошибок именно при такой оптимизации, если неправ - поправьте.

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

Edited by const

Share this post


Link to post
Share on other sites

4 hours ago, jcxz said:

Где же это видно? Вы неправы. Видно, что есть некая внешняя функция foo(), а также видно что glb - глобальная. А значит может изменяться например внутри той же foo(). А значит - она не может быть "всегда равна 0". Поэтому "выкинуть всё" - нельзя ни в каком случае. Была бы glb объявлена со "static" - другое дело.

как бы да, но нет, foo() никогда не будет вызвана так как и glb и sv проинициализованны нулями, соответственно менять glb больше некому, а в коротком примере ничего больше и нет.

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

 

Share this post


Link to post
Share on other sites

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

вынесите ф-цию foo в другой файл. Неужели и в таком случае выкинет.

Я так и сделал, разумеется. Выкинул. Повторюсь, это при LTO. Поэтому говорю, что при High balanced в IAR возможно подобное поведение, т.к. в pdf-ке описания, которое я смог нагуглить за наносекунды, написано, что в этом случае компилятор может анализировать содержимое памяти для осуществления оптимизаций.

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

Как может алгоритм зависить от уровня оптимизации?

Вопрос одновременно и простой и сложный, чтобы ответить на него вот так, с пыру)) Компилятор не транслирует строчки Си-кода в ассемблер... На основе Си-кода строится аналитическое дерево для выявления поведенческой модели. И именно этот механизм позволяет осуществлять различные оптимизации, такие, которые здоровому человеку в голову не придут. И главное правило оптимизатора - не ломать побочные эффекты программы, если они имеют смысл.

Поэтому да, отладка кода у меня не выше -O1 (почти всегда -O0), финальный релиз тестируется и отдается в продакшн только в -Obalanced + LTO. Потому что при повышенных агрессивных оптимизациях всплывает очень много скрытых багов, которые можно поймать и починить.

Share this post


Link to post
Share on other sites

extern void foo(uint8_t b);

uint8_t glb;

void tst(void)
{
  static uint8_t sv;
  uint8_t tmp;

  if (sv != (glb & (1 << 6))) {
    sv = (glb & (1 << 6));
    tmp = (sv)? 0x00 : 0xFF;
    foo(tmp);
  }

}

int main()
{ 
  while(1) {
    
    glb = GPIOA->IDR;
    tst();
    
  }
}

ф-ция foo (в др. файле)

void foo(uint8_t b)
{
  GPIOB->ODR = b;
}

так не выкинет. У меня с добавлением строк работы с портами листинг не поменялся - есть ошибка

     40          int main()
     41          { 
   \                     main:
   \   00000000   0xB570             PUSH     {R4-R6,LR}
   \   00000002   0x....             LDR.N    R5,??DataTable3_1
   \   00000004   0x....             LDR.N    R6,??DataTable3_2  ;; 0x40020010
   \   00000006   0xE001             B.N      ??main_0
     42            while(1) {
     43              
     44              glb = GPIOA->IDR;
     45              tst();
   \                     ??main_1:
   \   00000008   0x.... 0x....      BL       foo
   \                     ??main_0:
   \   0000000C   0x6830             LDR      R0,[R6, #+0] // читаем порт
   \   0000000E   0x7869             LDRB     R1,[R5, #+1] // sv
   \   00000010   0x7028             STRB     R0,[R5, #+0] // glb = GPIOA->IDR
   \   00000012   0x7828             LDRB     R0,[R5, #+0] // glb
   \   00000014   0xF000 0x0240      AND      R2,R0,#0x40 // glb & (1 << 6)
   \   00000018   0x4291             CMP      R1,R2
   \   0000001A   0xD0F7             BEQ.N    ??main_0
   \   0000001C   0x7068             STRB     R0,[R5, #+1] // sv = glb (без маскирования)
   \   0000001E   0x0640             LSLS     R0,R0,#+25
   \   00000020   0xBF4C             ITE      MI 
   \   00000022   0x2000             MOVMI    R0,#+0
   \   00000024   0x20FF             MOVPL    R0,#+255
   \   00000026   0xE7EF             B.N      ??main_1
     46              
     47            }
     48          }

 

Edited by const

Share this post


Link to post
Share on other sites

1 минуту назад, const сказал:
int main()
{ 
  while(1) {
    
    glb = GPIOA->IDR;
    tst();
    
  }
}

так не выкинет. У меня с добавлением строк работы с портами листинг не поменялся - есть ошибка

Ну так конечно не выкинет, так как присвоение glb требует порождения побочного эффекта - доступа к volatile-объекту.

7 минут назад, const сказал:

так не выкинет. У меня с добавлением строк работы с портами листинг не поменялся - есть ошибка

Вот теперь да, можно сказать, что ошибка есть.

Share this post


Link to post
Share on other sites

2 часа назад, Arlleex сказал:

CLang на максимальной оптимизации и LTO просто выкинул весь код. И правильно сделал.

Нет неправильно. Или ваш тест был некорректный.

glb - глобальная. Которая может модифицироваться за пределами данного кода. 

2 часа назад, Arlleex сказал:

main() - точка входа в Си-программу, поэтому на момент входа все глобальные переменные без инициализации равны 0.

Ну и что?

Share this post


Link to post
Share on other sites

5 минут назад, jcxz сказал:

Нет неправильно. Или ваш тест был некорректный.

Тест ровно тот что ТС указал в первом топике.

Share this post


Link to post
Share on other sites

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

как бы да, но нет, foo() никогда не будет вызвана так как и glb и sv проинициализованны нулями, соответственно менять glb больше некому, а в коротком примере ничего больше и нет.

Ошибаетесь. Какой-то код мог быть выполнен и до main(). Например - запущен ISR или вообще - запущена ОС. Задачи которой и могут модифицировать glb уже после её инициализации. Пускай даже она без volatile.

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

Тест ровно тот что ТС указал в первом топике.

Код то тот, но в проекте IAR ТС-а могут быть и другие файлы (они должны быть - ведь у нас МК, где-то есть инициализация его периферии). И IAR их имел в виду. А вы в тесте взяли ровно только то, что написано в исходном сообщении.

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

×
×
  • Create New...