1. Assembler / Говнокод #7313

    +245

    1. 01
    2. 02
    3. 03
    4. 04
    5. 05
    6. 06
    7. 07
    8. 08
    9. 09
    10. 10
    11. 11
    cmp     DWORD PTR [esi+4], 0     ; if obj->curChip == 0
        push    ebx
        push    edi
        jne     SHORT $LN8@harddetect
        movzx   ebx, WORD PTR [esi+12]   ; ebx = obj->baseport;
        jmp     SHORT $LN9@harddetect
    $LN8@harddetect:
        mov     ax, WORD PTR [esi+12]    ;\
        add     ax, 2                    ; шедевр!
        movzx   ebx, ax                  ;/
    $LN9@harddetect:

    Не понравился размер кода после компиляции. Полез посмотреть. Особо забавной показалась скомпилированная незатейливая конструкция:

    unsigned short port = (curChip == 0 ? baseport : baseport + 2);

    Компилятор VC++ 2005, с оптимизацией по размеру генерируемого кода. Наоптимизировал :D

    Запостил: DemonId7, 22 Июля 2011

    Комментарии (17) RSS

    • > Наоптимизировал :D

      что-то мне говорит что у тебя там в коде реальное спагетти топов данных с результирующими неявными конвертациями - которые в асме становятся явными. и если это так, то я думаю что компилер сгенерил код подобающий тому что ты написал. например факт того что port был сконвертирован в 32бит число, наталкивает на мысли.
      Ответить
      • Нет там никакой принудительной конвертации, все это самодеятельность компилятора.
        Ответить
        • присвоение переменной одного типа переменной другого типа == неявное преобразование типов. таже херня с выражениями.
          Ответить
    • DemonId7
      Что тебя смущает? Использование лишнего регистра АХ? Это не стоит того, чтобы постить такой код сюда.
      Ответить
      • Лишнего? Две лишние 16-ти битные команды, плюс два ненужных префикса изменения разрядности команд, плюс лишний джамп. И это на пару строк кода:
        movzx   ebx, WORD PTR [esi+12]
            cmp     DWORD PTR [esi+4], 0
            push    ebx
            push    edi
            je      SHORT $LN8@harddetect
            inc     ebx
            inc     ebx
        $LN8@harddetect:

        Почти ровно в два раза короче и без тормозных префиксов.
        Ответить
        • > inc ebx
          > inc ebx
          LOL`D
          Попробуй вот так:
          cmp     DWORD PTR [esi+4], 0
              push    WORD PTR [esi+12]
              push    edi
              je         SHORT $LN8@harddetect
             add WORD PTR [esi+12], 2
          $LN8@harddetect:

          Минус две ненужных строки.
          Ответить
          • А потом был коннект к базе, занявший 70 ms.
            Ответить
          • Красава :) Измерять размер кода в строках исходника - это новое слово в программировании.
            1) "push word ptr [esi+12]" - по размеру соответствует двум командам "push ebx \ movzx ebx, [esi+12]", а в дальнейшем использование ebx, вместо значения на стэке, куда как компактнее и шустрее.
            2) портить выравнивание стэка без крайней необходимости бывает иногда больно.
            3) "add word ptr [esi+12], 2" - занимает 4 байта + байт префикса. Итого 5 байт вместо 2-х ("inc ebx" - 1 байт).
            4) главное, изменяя непосредственно значение baseport (esi+12) после нескольких вызовов будешь иметь в baseport что угодно, только не адрес порта.
            И это на пять строк кода. Страшно представить, что было бы, дай тебе задание написать код на десяток-другой тысченок строк :D
            Ответить
        • Этот код вовсе не экивалентен заявленному. Порт шестнадцатибитный, поэтому инкременировать нужно bx, а не ebx, иначе для входных значений 65535 и 65534 код будет работать неправильно.

          Насчёт переходов и лишнего регистра полностью согласен, можно и сократить. А вот movzx ebx,... и push ebx нужно переставить, иначе в стеке будет не то, что ожидалось.
          Ответить
          • Именно что порт 16-ти битный, потому в регистр DX запишутся лишь младшие 16-ть бит регистра EBX, отбросив ненужные старшие биты и получив корректное значение. Хотя согласен, компилятор мог этого и не учесть. А должен бы, ведь port явно записывается в DX.
            Push и movzx перепутал уже при копипасте, здесь окошко маленькое и плохо видно код.
            Ответить
            • Кстати, да. Если port имеет тип unsigned short, baseport того же типа, то непонятно, почему компилятор обнуляет старшую половину регистра ebx (не производя при этом таких же манипуляций с регистром eax, а просто используя ax).

              Вероятно, для хранения переменных половинки регистров он выделять не умеет, хотя для промежуточных вычислений — запросто. Может быть, просто страховка?
              Ответить
    • показать все, что скрытоvanished
      Ответить

    Добавить комментарий