Странности компилятора VS 2005

Тема в разделе "WASM.ZEN", создана пользователем AsmGuru62, 21 окт 2006.

  1. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Занятно, однако...

    Решил проверить код, генерируемый для такой конструкции (в RELEASE-е, разумеется):
    Код (Text):
    1. // Where: const[b]X[/b] - some values [i]define[/i]-ed earlier
    2. if (value==const1) { event1 (); return; }
    3. if (value==const2) { event2 (); return; }
    4. if (value==const3) { event3 (); return; }
    5. // ... more cases of the same
    Получил вот что:
    Код (Text):
    1. mov eax, value
    2.  
    3. cmp eax, const1
    4. jnz chk1
    5.  
    6. call event1
    7. ret
    8.  
    9. chk1:
    10. cmp eax, const2
    11. jnz chk2
    12.  
    13. call event2
    14. ret
    15.  
    16. chk2:
    17. cmp eax, const3
    18. jnz chk3
    19.  
    20. call event3
    21. ret
    22.  
    23. // ... и т.д.
    Странно, потому что постоянно происходит JMP вперёд, который как известно не предсказывается через статический алгоритм предсказания в процессоре. Чем "глубже" лежит константа для сравнения - тем больше должна падать производительность такого кода. По моему мнению, код должен быть такой:
    Код (Text):
    1. mov eax, value
    2.  
    3. cmp eax, const1
    4. jz do_case1
    5.  
    6. cmp eax, const2
    7. jz do_case2
    8.  
    9. cmp eax, const3
    10. jz do_case3
    11.  
    12. // ... и т.д.
    13.  
    14. do_case1:
    15. call event1
    16. ret
    17.  
    18. do_case2:
    19. call event2
    20. ret
    21.  
    22. do_case3:
    23. call event3
    24. ret
    25.  
    26. // ... и т.д.
    Чтобы процессор "проваливался" на следующие проверки - "проваливание" ведь не надо предсказывать.

    Заменил код на такой:
    Код (Text):
    1. if (value==const1) goto L1;
    2. if (value==const2) goto L2;
    3. if (value==const3) goto L3;
    4.  
    5. ...
    6.  
    7. L1: event1 (); return;
    8. L2: event2 (); return;
    9. L3: event3 (); return;
    10.  
    11. ...
    Результат в точности остался прежним! Или я неверно понимаю оптимизационные руководства от INTEL-а или компилятор глупит? Может кто подскажет что может быть причиной?
     
  2. Black_mirror

    Black_mirror Active Member

    Публикаций:
    0
    Регистрация:
    14 окт 2002
    Сообщения:
    1.035
    AsmGuru62
    А для такой конструкции тоже так поступает?
    Код (Text):
    1. if(v==c1) e1();
    2. else if(v==c2) e2();
    3. ...
    4. esle
    5. {
    6. }
    7. return;
     
  3. IceStudent

    IceStudent Active Member

    Публикаций:
    0
    Регистрация:
    2 окт 2003
    Сообщения:
    4.300
    Адрес:
    Ukraine
    AsmGuru62
    Просто релиз ни о чём не говорит. Нужно играться с ключами оптимизации. И когда сообщаете о сгенерированном коде, также нужно приводить ключи компилятора.

    Это тоже не оптимум. Если условий много, тогда по идее нужно вставить таблицу переходов (switch-table), иначе что-то типа такого:
    Код (Text):
    1. sub  max_const
    2. ja  j_default
    3. je  j_max_const
    4. cmp  (max_const - const_n) ; или дальнейшие вариации с sub
    5. je  j_const_n
     
  4. fr0b-p

    fr0b-p New Member

    Публикаций:
    0
    Регистрация:
    1 окт 2006
    Сообщения:
    118
    на уровне АСТ компайлер не видит goto с бубном. если константы из непрерывного диапазона то этот switch должен скомпилироваться в косвенный call.
     
  5. AsmGuru62

    AsmGuru62 Member

    Публикаций:
    0
    Регистрация:
    12 сен 2002
    Сообщения:
    689
    Адрес:
    Toronto
    Пробовал различные виды оптимизации - не помогает.
    Мне просто надо знать: какой код быстрее?
     
  6. green

    green New Member

    Публикаций:
    0
    Регистрация:
    15 июл 2003
    Сообщения:
    1.217
    Адрес:
    Ukraine
    AsmGuru62

    IMHO компилятор генерирует код, исходя из предположения, что положительный результат проверки более вероятен.
    Надо соответствующим образом писать исходный код.
    ---
    А насчёт jmp вперёд, то там где это актуально (т.е. в циклах) компилятор как раз делает jmp назад.