Дано: 32-х байтная строка ASCII символов ('0','1') Получить: шестнадцатиричное представление двоичной строки Код (Text): ;===================================================== bin_str db '10000111011001010100001100100001' ;===================================================== mov eax,bin_str call bin2hex ;===================================================== bin2hex: lea edx,[eax+32] mov ecx,0-32 align 16 @@: movzx ebx,byte[edx+ecx] and ebx,1 inc ecx lea eax,[eax*2+ebx] jnz @b ret ; eax = 0x87654321 ;===================================================== Мне этот вариант кажется тупым
А в чём тупость? Можно такой вариант (возможно тоже тупой): Код (Text): mov eax,offset bin_str call bin2hex align 16 bin2hex: mov edx,eax xor ecx,ecx @@: shl eax,1 add al, byte ptr[edx+ecx] sub al,30h inc ecx cmp ecx,32 jne @B ret Так на 1 регистр меньше используется. И быстрее на 9 тиков (118/109). И ebx не изменяется.
Если размер и ebx не поджимают, можно ещё быстрее (69 тиков) Код (Text): mov eax,offset bin_str call bin2hex align 16 bin2hex: mov ebx,eax xor ecx,ecx @@: mov edx,[ebx+ecx*4] shl eax,1 sub dx,3030h add al,dl shl eax,1 add al,dh bswap edx shl eax,1 sub dx,3030h add al,dh shl eax,1 add al,dl inc ecx cmp ecx,8 jnz @B ret
bogrus Тупость только в том, что ты eax забыл обнулить ) А вообще в данном случае тупой вариант ИМХО самый простой и компактный, а зачем тут скорость нужна не знаю. Ежели только ради развлечения Ну тогда вот вариант с разворотом на 4: Код (Text): ;eax = offset bin_str ;push edi lea edi,[eax+32] mov ecx,-32 xor eax,eax xor edx,edx @@: shl eax,4 mov dl,[edi+ecx] add dl,dl add dl,[edi+ecx+1] ;для 4-х бит and на каждый символ можно не делать, т.к. у нас только 30h и 31h add dl,dl add dl,[edi+ecx+2] add dl,dl add dl,[edi+ecx+3] and dl,0Fh add eax,edx add ecx,4 jnz @b ;pop edi ;ret
Пусть в памяти лежит текстовая строка "1101" Загрузим её в ЕАХ, получим ЕАХ=31303131h из-за little-endian. Выделим младшие биты каждого байта AND EAX,01010101h; EAX=01000101h Умножим на магическое число 08040201h Подробно этот процесс изображен на рисунке: Нужные биты собрались вместе, причём в нужном порядке. Можно использовать по назначению.
cresta На PIII твой первый вариант 360 тактов (чтение al после eax), второй 250 тактов, мой всего 80 leo Зачем eax обнулять? я ж его сдвигаю 32 раза, то что в нем было роли не играет captain cobalt Вот-вот, в эту сторону мне и хотелось пораскинуть мозгами
bogrus 32 перехода jnz в 3 раза быстрее чем 8 переходов?? Мдя... Вот уж действительно народ правду говорит: интел-отстой Или дело в shl? Интересно, а если на add eax,eax заменить? На атлоне это одинаково.
cresta Это зависит от тела цикла, твоё ~33 такта, маё ~2.5, вот и умножь на кол-во проходов. А интел не отстой, он простые инструкции может выполнять за 0.25-0.5 такта, а вот атлон, если не ошибаюсь по 1-му на каждую. А тут дело не shl или add, а именно в обращении к части регистра после целого, у leo кстати побыстрее, ~70
bogrus Насчет eax, пардон. А говоришь тупой вариант, это я тупой сразу не сообразил Насчет ~70 тиков на PIII. Если без call\ret и c align 16, то у меня получается 63 тика. А супервариант captain cobalt аж 57 !
bogrus А откуда эта инфо: Если речь о тиках, а не тактах из справочника, то у меня получается ~7.5 и ~3.4 соответственно. И add с частью регистра после shl для Pentium'а имеет такие катастрофические последствия? leo А как ты реализовал ?
cresta Из теста на PIII, не во всяком справочнике можно увидеть данные по пенальти, я супервариант сделал пока так (~50): Код (Text): bin2hex: lea edx,[eax+32] mov ecx,-32 align 16 @@: mov ebx,[edx+ecx] and ebx,0x01010101 imul ebx,0x08040201 shl ebx,4 shld eax,ebx,4 add ecx,4 jnz @b
cresta > А как ты реализовал „супервариант captain cobalt “? По простому Код (Text): ;push edi, push esi, pus ebx lea edi,[eax+32] mov ecx,-32 mov esi,08040201h xor ebx,ebx ;на всякий случай, хотя bogrus учит что не нужно ;) @@: mov eax,[edi+ecx] and eax,01010101h mul esi shr eax,24 shl ebx,4 add ebx,eax add ecx,4 jnz @b mov eax,ebx ;pop ebx, pop esi, pop edi, ret PS: ну вот, пока писАл bogrus уже свой вариант запостил
Для удобства сменил константу на 0x80402010, теперь ~40 Код (Text): bin2hex: lea edx,[eax+32] mov ecx,-32 align 16 @@: mov ebx,[edx+ecx] and ebx,0x01010101 imul ebx,0x80402010 shld eax,ebx,4 add ecx,4 jnz @b
Интересно, для Атлона получается пенальти либо не возникают, либо они очень слабо сказываются. Похоже, вся оптимизация без указания конкретной модели процессора - это пшик Надо специально оговаривать: предлагать варианты для PIII или для PIV или для Атлона. Самые быстрые у меня оказались супер leo - 55 тиков (даже с push esi,edi/pop edi,esi) мой второй - 69 тиков первый leo - 70 тиков супер bogrus - 79 тиков
Оптимизация по размеру (13 байт включая ret и cld) Код (Text): ; in: esi - pointer to ASCII string (32 bytes long) ; out: eax - converted hex value xor edx, edx cld inc edx @@: lodsb shr al, 1 rcl edx, 1 jnc @b xchg eax, edx ret ЗЫ: в данном случае счётчик в лишнем регистре не нужен.
cresta Прально, каждый меряет на своем и говорит результат, а при использовании делаешь детект ЦПУ и идешь по нужной ветке, конечно если скорость нуна 74936217__detect.exe
13 байт, но не портит esi (fastcall конвенция) Код (Text): bin2hex: xor eax, eax inc eax @@: cmp [byte ecx], 31 ctc inc ecx rcl eax, 1 jnb @b retn
Догадайтесь с 3х попыток какой вариант быстрее на P4 Код (Text): 196 второй вариант cresta (P4 страшно не любит bswap и не долюбливает shl - лучше add ;) 160 исходный вариант bogrus 112 первый вариант captain_cobalt & bogrus c shld 92 последний вариант bogrus с 80402010 и shld 84 если в первом варианте заменить shl+shld на shr+shl+add 64 скромный туповатый вариант leo с разворотом на 4 Туповатые P4 просто обожают туповатые варианты bogrus Пральна то пральна, да вот скоко скушает сам детектор ? Может просто не нуна гнаться за рекордами на одном отдельно взятом ? PS: похоже Атлон тоже не любит shld, как и P4
Если в в последнем симпатичном варианте bogrus'а убрать shld, то наверное всех устроит По крайней мере на P3 без потерь, а на P4 - 68 тиков Код (Text): bin2hex: mov edx,eax mov ecx,32-4 ;от младших разрядов к старшим align 16 @@: mov ebx,[edx+ecx] and ebx,0x01010101 imul ebx,0x80402010 and ebx,0xF0000000 ;<--- !!! shr eax,4 or eax,ebx sub ecx,4 jge @b А как Атлон отреагирует ? Исправление: О-о, поспешишь - людей насмешишь. Тут ведь еще нужно and ebx,0xF0000000h добавить На P4 эта добавка мало сказывается (результат наполовину 68 или 72, с учетом дискрета 4 тика на P4)