Куда делась atoi

Тема в разделе "WASM.ASSEMBLER", создана пользователем kori, 1 дек 2005.

  1. kori

    kori New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2005
    Сообщения:
    4
    Народ подскажите траблу.Из asm проги нужно вызвать atoi(без нее никак) или что-то вроде нее. Посмотрел в отладчике прогу на с, эта гадостная функция ни откуда не вызывается, а ассемблируется вместе с прогой.Подскажите, как быть.
     
  2. Dr.Golova

    Dr.Golova New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2002
    Сообщения:
    348
    Написано давно, тут уже обсуждалось. Оптимизировалось по скорости. То что тут предлогалось скорости явно не добавляло, или резало функционал. Вобщем этот код должен работать как стандартный сишный atoi() не больше и не меньше =)
    Код (Text):
    1.  
    2. ;; crt atoi() implementation by Dr.Golova
    3. ;; [email=]mailto:[/email] dr_golova@mail.ru
    4. ;; compile it with NetWide Assembler (NASM)
    5. ;; nasmw.exe -o atoi.obj -f coff -L atoi.asm
    6.  
    7. bits 32
    8.  
    9. atoi:
    10.                 push    ebx
    11.                 mov     ecx, dword [esp+8]       ;; input string ptr
    12.  
    13. ;; scan and skip leading spaces
    14. .skip_space:
    15.                 movzx   eax, byte [ecx]
    16.                 cmp     eax, ' '
    17.                 jnz     short .check_sign
    18.                 inc     ecx
    19.                 jmp     short .skip_space
    20.  
    21. ;; check and save sign
    22. .check_sign:
    23.                 mov     edx, eax                 ;; save posible sign byte
    24.                 xor     ebx, ebx
    25.                 cmp     eax, '-'
    26.                 jz      short .check_char
    27.                 cmp     eax, '+'
    28.                 jnz     short .no_sign
    29. .check_char:
    30.                 inc     ecx
    31.                 movzx   eax, byte [ecx]
    32. .no_sign:
    33.                 sub     eax, '0'
    34.                 cmp     eax,  9
    35.                 ja      short .non_digit
    36.                 lea     ebx, [ebx+ebx*4]
    37.                 lea     ebx, [eax+ebx*2]
    38.                 jmp     short .check_char    
    39. .non_digit:
    40.                 cmp     edx, '-'                 ;; check sign byte
    41.                 jnz     short .done
    42.                 neg     ebx
    43. .done:
    44.                 mov     eax, ebx
    45.                 pop     ebx
    46.                 retn
    47.  
    48. end
    49.  
     
  3. Dr.Golova

    Dr.Golova New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2002
    Сообщения:
    348
  4. Ms Rem

    Ms Rem New Member

    Публикаций:
    0
    Регистрация:
    17 апр 2005
    Сообщения:
    1.057
    Адрес:
    С планеты "Земля"
    В ntdll.dll есть такая функция, если важен маленький размер, то используй ее.



    З.Ы. Я пользуюсь StrToIntA из shlwapi.dll
     
  5. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Если уж речь зашла о спаривании инструкций
    Код (Text):
    1.  
    2.                 inc     ecx
    3.                 movzx   eax, byte [ecx]


    можно заменить на
    Код (Text):
    1.  
    2.                 movzx   eax, byte [ecx+1]
    3.                 add     ecx, 1 ; inc     ecx ; как больше нравится
     
  6. leo

    leo Active Member

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

    Я бы на свой вкус тоже movzx использовал, но на твой многозначительный [beep] отвечаю ;))

    Во-первых, понятие спаривания инструкций благополучно скончалось вместе с последними реликтовыми PMMX. И инструкция movzx eax,[mem] на PPlain\PMMX как раз и является неспариваемой и ее рекомендовалось заменять на xor eax,eax + mov al, byte[mem]

    Во-вторых, ты наверное имел ввиду не спаривание, а проблему partial registers. Но в рассматриваемом случае она благополучно решается путем вставки одной единственной xor eax,eax в начало функции, поэтому кроме лишних 2-х байт кода никаких других отрицательных последствий от использования операций с AL, а не EAX тутa нема :)))

    Хотя с movzx конечно "правильнее" ;)



    PS: Повторив матчасть ;), приходим к выводу что с AL код получается короче, т.к. 1) movzx на байт длиннее mov, 2) cmp\sub al,imm8 в минимальной кодировке - два байта, а cmp\sub eax,imm8 - минимум 3
     
  7. cresta

    cresta Active Member

    Публикаций:
    0
    Регистрация:
    13 июн 2004
    Сообщения:
    2.257
    Вообще то atoi находится в msvcrt.dll
     
  8. leo

    leo Active Member

    Публикаций:
    0
    Регистрация:
    4 авг 2004
    Сообщения:
    2.542
    Адрес:
    Russia
    Да в msvcrt, но реализована она там с ужасными наворотами, а вот в ntdll гораздо проще - по кр.мере в XP
     
  9. S_T_A_S_

    S_T_A_S_ New Member

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




    Можно и так сказать, если под спариванием понимать выполнение _двух_ команд. Назавём это спараллеливанием, глубокий смысл не поменяется. :)



    Вот это не может выполняться параллельно - зависимость по данным:
    Код (Text):
    1.  
    2.                 inc     ecx
    3.                 movzx   eax, byte [ecx]


    Если инструкции поменять местами - зависимость исчезает.



    >




    Вот здесь возможна зависимость по данным, которая мешает параллелиться:
    Код (Text):
    1.  
    2.                 mov     al, byte [ecx]
    3. ;...
    4.                 lea     ebx, [eax+ebx*2]
    хотя реально инструкции находятся далеко, и это может быть не заметно.
     
  10. Dr.Golova

    Dr.Golova New Member

    Публикаций:
    0
    Регистрация:
    7 сен 2002
    Сообщения:
    348
    Понял, исправлюсь :)
     
  11. leo

    leo Active Member

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

    > "здесь возможна зависимость по данным, которая мешает параллелиться"

    Совершенно верно ;) Причем эта зависимость точно такая же как и при замене mov al,[ecx] на movzx eax,[ecx] (ес-но при условии, что в начале цикла был xor)



    PS: А мануальные страшилки о предпочтительности movzx eax перед mov al относятся к случаю, когда xor eax стоит непосредственно перед mov al и тогда ес-но имеем и зависмость mov от xor и лишнюю нагрузку на декодер
     
  12. S_T_A_S_

    S_T_A_S_ New Member

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

     
  13. leo

    leo Active Member

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

    Угу, совершенно верно ;)

    У partial register access есть два implementation depended аспекта: 1) зависимость по данным, 2) возможный дополнительный штраф при чтении целого регистра после записи в частичный регистр

    В семействе P6 (включая Pentium M, model < 13) аллокатор назначает независимые темп-регистры операциям записи в EAX, AX, AH, AL не заботясь о соответствии данных в старших разрядах (по-видимому просто забивает нулями старшие разряды частичных темп-регистров). Поэтому в P6 операции записи в разные части одного регистра независимы по данным. Зато возникает проблема объединения данных при обращении к целому регистру после записи в частичный, т.к. проц должен скомбинировать (наложить) данные частичного регистра AL на текущее состояние всего EAX. Объединение данных происходит в момент отставки инструкции записи, а это задержка минимум в 6-7 тиков => partial register stall. Чтобы его избежать в P6 предусмотрено отслеживание обнуления 32-битных регистров операциями xor и sub. Если EAX был обнулен, то комбинировать нечего и ждать отставки mov AL,X незачем, т.к. текущий темп-регистр AL с нулевыми старшими разрядами по сути и есть текущее представление регистра EAX => no partial stall.

    В атлонах, P4 и старших моделях Pentium M есть только одна текущая копия GPR регистра, т.е. при записи в AL проц всегда берет содержимое текущего регистр EAX, перезаписывает младший байт и полученное значение является новым представлением всего регистра EAX. Поэтому 1) операция чтения\записи любой части регистра зависима по данным от предыдущей модификации всего или любой части этого же регистра, 2) кроме зависимости по данным никакого доп. штрафа при чтении целого регистра после частичной записи - нет. Никакого partial register stall нет, а есть обычная зависимость по данным с учетом того, что AX, AH, AL это ни какие-то особые регистры, а просто части единого EAX



    PS: Далеко однако нас занесло от atoi, и куда она делась - прям в соответствии с названием темы ;)
     
  14. S_T_A_S_

    S_T_A_S_ New Member

    Публикаций:
    0
    Регистрация:
    27 окт 2003
    Сообщения:
    1.754
    Думаю, документация содержит не более 20% информации. Смотри сам - al - один теневой регистр, eax - другой теневой регистр. Может, теневых регистров не хватит? :)
     
  15. leo

    leo Active Member

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

    Неправильно думаешь ;) Инфы достаточно, если конечно не зацикливаться только на последних мануалах IA-32. В частности про partial registers в P6 есть инфа в мануалах по оптимизации от 1997 и 1999 гг. Да и в статьях Intel Technology Jornal можно много полезного найти, и А.Фог свою инфу не из пальца высосал ;)



    Переименование регистров это основа основ out-of-order execution. Чтобы не усложнять логику переименования, при любой модификации архитектурного регистра EAX, ему назначается новый физический регистр. Это делается потому, что перед операцией модификации могла быть одна или несколько инструкций чтения этого регистра и за счет переупорядочивания эти инструкции могут в итоге выполниться позже, чем запись нового значения в EAX. А помнить предисторию чтений всех регистров (GPR,FPU,XMM) ес-но накладно - проще при каждой модификации назначать новый физический регистр.

    А по поводу того, что регистров не хватит переживать не стоит, т.к. число физических регистров связано с емкостью ROB, а большинство микроопов могут изменять только один регистр. Раз число мопов в ROB ограничено, то совершенно неважно изменяют они разные регистры или один и тот же - если и будет переполнение, то оно будет определяться числом мопов, а не тем какие регистры они изменяют
     
  16. kori

    kori New Member

    Публикаций:
    0
    Регистрация:
    1 дек 2005
    Сообщения:
    4
    Спосибо всем, кто помог.Все получилось