Вот на такой код: Код (Text): for(int i=0;i<10;i++) MessageBox(0,0,0,0); МС-компиллер дает такой асм: Код (Text): .00401000: push esi .00401001: mov esi,MessageBoxA ;USER32 .00401007: push edi .00401008: mov edi,00000000A ---↑ (1) .0040100D: lea ecx,[ecx][00] .00401010: push 000 .00401012: push 000 .00401014: push 000 .00401016: push 000 .00401018: call esi .0040101A: sub edi,001 ;"☺" .0040101D: jne .000401010 ---↑ (2) .0040101F: pop edi .00401020: xor eax,eax .00401022: pop esi Оптимизация "по всем понтам на скорость". Во-первых не ясно, почему уменьшение счетчика делается через sub а не через dec. Далее, зачем MessageBoxA запихивать в регистр? Если уж на то пошло, могли бы и ноль в регистре хранить. Ну и совсем непонятно на кой хрен нужна команда "lea ecx,[ecx][00]" ? И маленький вопросик в довесок: можно ли заставить компиллер константные циклы разворачивать?
_DEN_ Ну с первыми двумя все понятно: sub и dec не рекомендованы интел и втюне на них даже плюется; в регистр пихать хотябы затем чтоб в цикле вызов без референса к памяти. А вот с lea ecx,[ecx][00] явно лошит и в 8й студии такого уже нет: Код (Text): _main PROC ; COMDAT ; Line 4 push esi ; Line 5 mov esi, DWORD PTR __imp__MessageBoxA@16 push edi mov edi, 10 ; 0000000aH npad 3 $LL3@main: ; Line 6 push 0 push 0 push 0 push 0 call esi sub edi, 1 jne SHORT $LL3@main pop edi ; Line 7 xor eax, eax pop esi ret 0 _main ENDP [апдейт] Чета сразу не заметил, что lea это паддинг - так что и с этим притензии к компилеру сняты...
semen И как это понимать? Это что такое? q_q Все default кроме: Optimization: - Global optimization: yes - Favor size or speed: favor fast code - Optimize for processor: Pentium 4 and above - Optimize for windows application: yes Code generation: - Enable enchanced instruction set: SSE2
_DEN_ Ну во-первых на норсвуде они не дабл спид. Есть ли еще противопоказания не помню, но помню точно что во всех манах интела это не рекомендованные инструкции и must be avoid. А про паддинг сам почитай, скорее всего npad 3 и оттранислировался ассемблером в lea, тока 7&8я студия паддит на 8\16, а не на 4.
semen Тоесть теперь dec медленнее чем sub? Я познаю мир с подгузниками хаггис... В голове не укладывается.
_DEN_ Ну да - на норсвуде медленее, а на прескотте одинаково, но типа интел уже сказал что ему на эти инструкции наплевать и в будущем может стать снова медленее =) [апдейт] вобщем вот: Код (Text): Assembly/Compiler Coding Rule 42. (M impact, H generality) inc and dec instructions should be replaced with an add or sub instruction, because add and sub overwrite all flags, whereas inc and dec do not, therefore creating false dependencies on earlier instructions that set the flags. ну и плюс к этому на норсвуде and\sub пол такта, а inc\dec 1 такт.
semen Мда... Код (Text): for(int i=0;i<10;i++) { MessageBoxA(0,0,0,0); MessageBoxW(0,0,0,0); MessageBeep(0); GetMessage(0,0,0,0); } Тут он уже счетчик положил в стек. И кстати начало цикла не выравнено. И что самое интересное - в начале и в конце push / pop ecx, но ecx нигде не юзается?.. Код (Text): .00401000: push ecx .00401001: push ebx .00401002: mov ebx,MessageBeep ;USER32 .00401008: push ebp .00401009: mov ebp,GetMessageA ;USER32 .0040100F: push esi .00401010: mov esi,MessageBoxA ;USER32 .00401016: push edi .00401017: mov edi,MessageBoxW ;USER32 .0040101D: mov d,[esp][10],00000000A ---↑ (1) .00401025: push 000 .00401027: push 000 .00401029: push 000 .0040102B: push 000 .0040102D: call esi .0040102F: push 000 .00401031: push 000 .00401033: push 000 .00401035: push 000 .00401037: call edi .00401039: push 000 .0040103B: call ebx .0040103D: push 000 .0040103F: push 000 .00401041: push 000 .00401043: push 000 .00401045: call ebp .00401047: sub d,[esp][10],000000001 ;"☺" .0040104C: jne .000401025 ---↑ (2) .0040104E: pop edi .0040104F: pop esi .00401050: pop ebp .00401051: xor eax,eax .00401053: pop ebx .00401054: pop ecx .00401055: retn 00010 ;" ►"
_DEN_ Ну тут пускай кто-нибудь компетентнее меня отвечает... Непортящиеся регистры видимо закончились и что делать с референсом к памяти пофиг, а с выравниванием - видимо линкер поставит main так, что цикл станет выровненным.
_DEN_ Уже проверил, что это не так, но ведь возможно сам main подвинуть так, что цикл станет выровненным - короче хз что с выравниванием - нет его, может она более 8 нопов не делает, хз вобщем - не знаю я, скорее всего trade-off какой-то, но глюков компилятора на этих примерах я не вижу.
в начале и в конце push / pop ecx, но ecx нигде не юзается?.. в блоке присутствует вызов API а он не обязан сохранять ecx - поэтому компилятор и вставил push/pop
Sickle Ай здорово как Осталось только понять, нафига это надо - это вся прога, а не какой-то фрагмент. Можно подумать кернел упадет при закрытии процесса, если ecx не сохранить.
_DEN_ Да не - на этих примерах самый что ни на есть нормальный, а вот здесь я действительно ляпы собирал http://wasm.ru/forum/index.php?action=vthread&forum=7&topic=9416&page=0 - больше пока не нашел.
_DEN_ Что ты так все быстро решаешь - ecx мог crt понадобиться - main этож не entry point прикладухи. Она вообще без компиляции crt c WPO не может понять что ecx crt не нужен.
_DEN_ Ну и что? Показатель будет, если она сохранит не нужный регистр во вложенной в main функции, причем со включенным WPO.