Оптимизация

Тема в разделе "WASM.A&O", создана пользователем Lyrik, 13 фев 2005.

  1. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    Здравствуйте! У меня такой вопросик: мона ли тут что-нить оптимизировать, и если да, то, что конкретно:
    Код (Text):
    1. int Lyrik(const char* buff)
    2. {
    3.     long total = 0;
    4.     _asm
    5.     {
    6.         xor eax,eax;
    7.         xor ecx,ecx;
    8.         mov esi,buff;
    9.     cikl:
    10.         mov cl,byte ptr [esi];
    11.         test cl,cl;
    12.         jz endstr;
    13.         cmp cl,'0';
    14.         jge ok;
    15.     opt:
    16.         inc esi;
    17.         jmp cikl;
    18.     ok:
    19.         cmp cl,'9';
    20.         jle okey;
    21.         jmp opt;
    22.     okey:
    23.         sub cl,'0';
    24.         imul eax,0xA;
    25.         add eax,ecx;
    26.         jmp opt;
    27.     endstr:
    28.         mov esi,buff;
    29.         mov cl, byte ptr [esi];
    30.         cmp cl,'-';
    31.         jne kon;
    32.         neg eax;
    33.     kon:
    34.         mov total,eax;
    35.     }
    36.     return total;
    37. }
     
  2. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    для начала, мона убрать все строки, где есть total.

    а что должен делать __asm код ?
     
  3. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Можно избавиться от секции opt:


    Код (Text):
    1.         xor eax,eax;
    2.         xor ecx,ecx;
    3.         mov esi,buff;
    4.         dec esi;
    5.     cikl:
    6.         inc esi;
    7.         mov cl,byte ptr [esi];
    8.         test cl,cl;
    9.         jz endstr;
    10.         cmp cl,'0';
    11.         jl cikl;
    12.     ok:
    13.         cmp cl,'9';
    14.         jg cikl;
    15.         sub cl,'0';
    16.         imul eax,0xA;
    17.         add eax,ecx;
    18.         jmp cikl;
    19.     endstr:
    20.         mov esi,buff;
    21.         mov cl, byte ptr [esi];
    22.         cmp cl,'-';
    23.         jne kon;
    24.         neg eax;
    25.     kon:
    26.         mov total,eax;
     
  4. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Ну и можно удалить cmp cl,'0', сразу заменив его на sub cl,'0'


    Код (Text):
    1.         xor eax,eax
    2.         xor ecx,ecx
    3.         mov esi,buff
    4.         dec esi
    5.     cikl:
    6.         inc esi
    7.         mov cl,byte ptr [esi]
    8.         test cl,cl
    9.         jz endstr
    10.         sub cl,'0'
    11.         js cikl
    12.         cmp cl,9
    13.         jg cikl
    14.         imul eax,0xA
    15.         add eax,ecx
    16.         jmp cikl
    17.     endstr:
    18.         mov esi,buff
    19.         mov cl, byte ptr [esi]
    20.         cmp cl,'-'
    21.         jne kon
    22.         neg eax
    23.     kon:
     
  5. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Lyrik
    Код (Text):
    1. imul eax,0xA
    2. add eax,ecx
    замени на
    Код (Text):
    1. lea eax,[eax+eax*4]
    2. lea eax,[ecx+eax*2]




    S_T_A_S_

    что должен делать __asm код

    Afaik atoi/atol.
     
  6. masquer

    masquer wasm.ru

    Публикаций:
    0
    Регистрация:
    13 сен 2002
    Сообщения:
    890
    Адрес:
    Николаев
    Lyrik

    А такой вопросик - на предмет чего оптимизируем? Скорость, размер, удобочитаемость?

    Кол-во переходов, конечно, потрясает. Такое подойдет?
    Код (Text):
    1.     mov esi, buff
    2.     dec esi
    3.     xor eax, eax
    4.     xor ebx, ebx
    5. @@:
    6.     inc esi
    7.     movzx eax, byte ptr [esi]
    8.     test eax, eax
    9.     jz @F
    10.     sub eax, 30h
    11.     sbb edx, edx
    12.     sub eax, 10
    13.     sbb ecx, ecx
    14.     not edx
    15.     and edx, ecx
    16.     jz @B
    17.     lea ebx, [ebx+ebx*4]
    18.     lea ebx, [eax+ebx*2+10]
    19.     jmp @B
    20. @@:
    21.     mov esi, buff
    22.     movzx eax, byte ptr [esi]
    23.     cmp eax, "-"
    24.     jnz @F
    25.         neg ebx
    26. @@:
    27.     mov total, ebx
     
  7. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    q_q



    Разве atoi/atol обработает строку 1 ! 2 " 3 # 4 $ 5 % 6 & 7 ' 9 ( 9 ) 0

    ?
     
  8. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Код может переводить строку вида 1234 руб 56 коп в количество копеек :)
     
  9. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    S_T_A_S_

    Оригинальная версия вернет 1, т.к. закончит преобразование, встретив пробел между "1" и "!".



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

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    глядя на избыточный код первоначальной версии, сложно сказать что исходные данные идеальны.


    Код (Text):
    1.  
    2. int __fastcall my_atoi(const char * s)
    3. {
    4.     while( *s++ <= ' ' )
    5.         ;
    6.     int sign = s[-1] != '-';
    7.     s -= sign--;
    8.     int res = 0;
    9.     while( true )
    10.     {
    11.         unsigned digit = *(unsigned char *)s++ - '0';
    12.         if( digit <= 9 )
    13.             res = 10 * res + digit;
    14.         else
    15.             return (sign ^ res) - sign;
    16.     }
    17. }


    на всякий случай дизасм:
    Код (Text):
    1. 0040103D  /$  8A01          /mov     al, [ecx]
    2. 0040103F  |.  41            |inc     ecx                            
    3. 00401040  |.  3C 20         |cmp     al, 20
    4. 00401042  |.^ 7E F9         \jle     short 0040103D
    5. 00401044  |.  33C0          xor     eax, eax
    6. 00401046  |.  8079 FF 2D    cmp     [byte ecx-1], 2D
    7. 0040104A  |.  56            push    esi
    8. 0040104B  |.  0F95C0        setne   al
    9. 0040104E  |.  8BF0          mov     esi, eax
    10. 00401050  |.  2BCE          sub     ecx, esi
    11. 00401052  |.  4E            dec     esi
    12. 00401053  |.  33C0          xor     eax, eax
    13. 00401055  |.  EB 05         jmp     short 0040105C
    14. 00401057  |>  6BC0 0A       /imul    eax, eax, 0A
    15. 0040105A  |.  03C2          |add     eax, edx                        
    16. 0040105C  |>  0FB611         movzx   edx, [byte ecx]
    17. 0040105F  |.  83EA 30       |sub     edx, 30
    18. 00401062  |.  41            |inc     ecx                            
    19. 00401063  |.  83FA 09       |cmp     edx, 9
    20. 00401066  |.^ 76 EF         \jbe     short 00401057
    21. 00401068  |.  33C6          xor     eax, esi
    22. 0040106A  |.  2BC6          sub     eax, esi
    23. 0040106C  |.  5E            pop     esi                              
    24. 0040106D  \.  C3            retn
     
  11. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    masquer

    > "Такое подойдет?"

    Подойдет, только имхо намудрил чуток :)



    Может проверку диапазона проще так делать
    Код (Text):
    1.     sub eax,30h
    2.     setb dl      ;1 если < '0', 0 если >= '0'
    3.     cmp eax,9
    4.     sbb dl,0     ;'0'..'9' -> -1, иначе 0 или 1
    5.     jge @B
     
  12. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Нужны ли _вообще_ все эти проверки?

    Вариант с одним переходом (если не считать ведущие whitespace) :
    Код (Text):
    1. int a2i(const char * s)
    2. {
    3.     while( *s++ <= ' ' )
    4.         ;
    5.     int sign = s[-1] != '-';
    6.     s -= sign--;
    7.     int res = 0;
    8.     unsigned digit = 0;
    9.     do
    10.     {
    11.         res = 10 * res + digit;
    12.         digit = *(unsigned char *)s++ - '0';
    13.     }
    14.     while( digit <= 9 );
    15.     return (sign ^ res) - sign;
    16. }

    Код (Text):
    1.  
    2. 0040103D  /$  8A01          /mov     al, [ecx]
    3. 0040103F  |.  41            |inc     ecx                            
    4. 00401040  |.  3C 20         |cmp     al, 20
    5. 00401042  |.^ 7E F9         \jle     short 0040103D
    6. 00401044  |.  33D2          xor     edx, edx                        
    7. 00401046  |.  8079 FF 2D    cmp     [byte ecx-1], 2D
    8. 0040104A  |.  56            push    esi
    9. 0040104B  |.  0F95C2        setne   dl
    10. 0040104E  |.  33C0          xor     eax, eax
    11. 00401050  |.  2BCA          sub     ecx, edx                        
    12. 00401052  |.  4A            dec     edx                              
    13. 00401053  |.  33F6          xor     esi, esi
    14. 00401055  |>  6BC0 0A       /imul    eax, eax, 0A
    15. 00401058  |.  03C6          |add     eax, esi
    16. 0040105A  |.  0FB631        |movzx   esi, [byte ecx]
    17. 0040105D  |.  83EE 30       |sub     esi, 30
    18. 00401060  |.  41            |inc     ecx                            
    19. 00401061  |.  83FE 09       |cmp     esi, 9
    20. 00401064  |.^ 76 EF         \jbe     short 00401055
    21. 00401066  |.  33C2          xor     eax, edx                        
    22. 00401068  |.  2BC2          sub     eax, edx                        
    23. 0040106A  |.  5E            pop     esi                              
    24. 0040106B  \.  C3            retn
     
  13. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    S_T_A_S_

    Да, ты прав: отдельное сравнение на < '0' действительно не нужно. Достаточно
    Код (Text):
    1.     sub eax,30h
    2.     cmp eax,9
    3.         ;беззнаковое сравнение jbe или ja
    А так, в твоем варианте только imul на lea заменить и будет ОК.
     
  14. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    Спасибо, что ответили.



    Естественно на скорость выполнения. Чтобы меньше занимало тактов процессора :)

    Так что какой последний вариант?
     
  15. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    leo



    Да я не про те проверки - пока не понятно, нужно ли atoi или всё же оптимизировать первоначальный вариант (смысл которого мне не совсем понятен).





    Lyrik



    ты так и не прояснил условия задачи.

    если нужен atoi, бери последний вариант, но перед ним напиши:

    #pragma optimize( "gt", on )

    чтобы был msvc поставил lea вместо умножения.

    (хотя imho такие задачи оптимизировать по скорости не нужно)

    если ведущих пробелов не будет, можно убрать первый цикл.
     
  16. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    Как раз я хочу написать своего рода универсальный atoi, чтобы были и пробелы и буквы и т.д.

    Опции компилера ставить не хочу. Хочу оптимизировать вручную, то, что я написал - естсественно мой пробный и не особо быстрый вариант. И я обратился к Вам за помощью :)
     
  17. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Lyrik

    Посмотреть, как в современных библиотеках реализована atoi не пробовал?
     
  18. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    В современных - нет

    Вот вариант, как я понял самый оптимальный:
    Код (Text):
    1. int Lyrik(const char* buff)
    2. {
    3.     long total = 0;
    4.     _asm
    5.     {
    6.         xor eax,eax
    7.         xor ecx,ecx
    8.         mov esi,buff
    9.         dec esi
    10.     cikl:
    11.         inc esi
    12.         mov cl,byte ptr [esi]
    13.         test cl,cl
    14.         jz endstr
    15.         sub cl,'0'
    16.         js cikl
    17.         cmp cl,9
    18.         jg cikl
    19.         lea eax,[eax+eax*4]
    20.         lea eax,[ecx+eax*2]
    21.         jmp cikl
    22.     endstr:
    23.         mov esi,buff
    24.         mov cl, byte ptr [esi]
    25.         cmp cl,'-'
    26.         jne kon
    27.         neg eax
    28.     kon:
    29.         mov total,eax
    30.     }
    31.     return total;
    32. }
     
  19. q_q

    q_q New Member

    Публикаций:
    0
    Регистрация:
    5 окт 2003
    Сообщения:
    1.706
    Lyrik

    Ты кроме третьего и четвертого ответы читал?
     
  20. Lyrik

    Lyrik New Member

    Публикаций:
    0
    Регистрация:
    14 янв 2005
    Сообщения:
    11
    Читал, извините, не то опубликовал <_<
    Код (Text):
    1. int Lyrik(const char* buff)
    2. {
    3.     long total = 0;
    4.     _asm
    5.     {
    6.         xor eax,eax
    7.         mov esi,buff
    8.         dec esi
    9.     cikl:
    10.     xor ecx,ecx
    11.         inc esi
    12.         mov cl,byte ptr [esi]
    13.     test cl,cl
    14.     jz endstr
    15.     sub ecx,0x30
    16.     cmp ecx,9
    17.     ja cikl
    18.     lea eax,[eax+eax*4]
    19.     lea eax,[ecx+eax*2]
    20.         jmp cikl
    21.     endstr:
    22.         mov esi,buff
    23.         mov cl, byte ptr [esi]
    24.         cmp cl,'-'
    25.         jne kon
    26.         neg eax
    27.     kon:
    28.     mov total,eax
    29.     }
    30.     return total;
    31. }