|
|
| Посл.отвђт | Сообщенiе |
|
|
Дата: Апр 23, 2003 11:39:08 Вот char LRC(char* buf){ char res = 0; for (;*buf != ETX;)res ^= *buf++; res ^= *buf++; *buf = res; return res; } я попробовал так, но может кто посоветует лучше? MOV eax, 0 MOV ecx, 0 jm01: MOV DL, Pin[ecx] XOR AL,DL INC ecx CMP DL,3 JNE jm01 MOV Pin[ecx], AL RET |
|
|
Дата: Апр 23, 2003 12:17:13 mov ebx,buf ; или lea или mov offset xor al,al ; res = 0 for_begin: cmp byte ptr [ebx],ETX ; for (;*buf != ETX;) jz for_end xor al,byte ptr [ebx] ; res ^= *buf inc ebx ; *buf++ jmp short for_begin for_end: xor al,byte ptr [ebx] ; res ^= *buf inc ebx ; *buf++ mov [ebx],al ; *buf = res |
|
|
Дата: Апр 23, 2003 12:25:27 Спасибо. :) |
|
|
Дата: Апр 24, 2003 03:45:34 Еще забыл [code] mov buf,ebx ; чтобы учесть, что buf изменился [/code] |
|
|
Дата: Апр 26, 2003 00:00:15 P2M Вы забыли push ebx / pop ebx чтобы учесть, что buf изменился Не надо учитывать - локальная переменная |
|
|
Дата: Апр 26, 2003 03:41:15 · Поправил: boozook Такой вариант должен быть лучше: LRC proc uses edi pbuf:PCHAR mov edi,pbuf mov ah,[edi] ; первый(или последний) xor здесь mov al,ETX scasb ; ETX ?= *buf++ je endfor ; если == -> конец startfor: xor ah,[edi] ; res ^= *buf scasb ; ETX ?= *buf++ jne startfor ; если != -> продолжаем endfor: mov al,ah mov [edi],ah ; *buf = res ret LRC endp ... start: cld ; сбросить флаг направления ... call LRC ... |
|
|
Дата: Апр 26, 2003 11:05:02 · Поправил: P2M boozook Про push/pop спорить не буду, не обратил внимание, что надо оформить как функцию. Можно заменить EBX на EDX/ECX, тогда можно без push/pop. Не надо учитывать - локальная переменная А вот это не обязательно, т.к. вызывающий код не показан. Чтобы не быть голословным приведу _гипотетический_ пример. [code] .data buf db '1234567890', 0 .code ; Ищет в заданной строке '5' ; Изменяет переданный адрес, так чтобы он указывал на '5' или конец строки ; ; Возвращает ; ноль - '5' не найдена ; не ноль - '5' найдена fn1 PROC mov edx,[esp+4] xor eax,eax mov al,'5' @@: cmp ah,[edx] jz @F cmp al,[edx] jz @F inc edx jmp short @B @@: mov [esp+4],edx ; !!! сохранить and al,[edx] ret fn1 ENDP ; ; MessageBox заданной строки ; fn2 PROC mov eax,[esp+4] invoke MessageBox,0,eax,0,MB_OK ret fn2 ENDP ; ; Демонстрация использования одного параметра для двух функций. ; main proc push offset buf call fn1 cmp al,'5' jnz @F call fn2 @@: pop eax ret main endp [/code] Разумеется такой "оптимизации" не получится с макросами подобными INVOKE. Ваш вариант кода безусловно имеет законченную форму, но я вижу в нем недостатки: 1) лишний SCASB; 2) CLD безопаснее делать внутри функции и добавить PUSHF/POPF; 3) afaik SCASB работает медленнее, чем пара CMP и INC. |
|
|
Дата: Апр 26, 2003 15:22:19 · Поправил: boozook P2M А вот это не обязательно, т.к. вызывающий код не показан. Это пример другой функции, и на asm'е. Не знаю возможно ли на Си сделать такую оптимизацию, но первоначальная процедура точно не предусматривает сохранения результата в стеке. Сишный компилятор может даже использовать это место под другую локальную переменную, после занесения значения buf в регистр. 1) лишний SCASB; у меня цикл начинается со второй строки процедуры, метку надо было назвать start_repeat :) 2) CLD безопаснее делать внутри функции и добавить PUSHF/POPF; Возможно. Скорее всего, по правилам - процедуры не обязаны сохранять этот флаг. Я точно не знаю. Но тогда зачем PUSHF/POPF? ;При низкоуровневой оптимизации, ее можно засунуть вместо ALING'a 3) afaik SCASB работает медленнее, чем пара CMP и INC. Опять же не уверен, но по-моему процессоры начиная с PPro обрабатывают 3 инструкции за такт, при условиях их упорядочивания 4-1-1 и (почти обязательном)отсутствии переходов. тогда: scasb ;3mops je endfor ;1 mop xor ah,[edi] ;1 mop , должны выполниться за один такт Да, еще. Подозреваю, что макрос proc всегда генерит такую лажу: push ebp mov ebp,esp ... leave ...и если заняться оптимизацией, учитывая все это (кроме ALIGN) код будет примерно таким: LRC proc ; pbuf:PCHAR cld xchg edi,[esp+4] ; будет быстрее если использовать: mov edx,edi; pop edi mov ah,[edi] ; первый(или последний) xor здесь mov al,ETX scasb ; ETX ?= *buf++ je endfor ; если == -> конец startfor: ;повторяем это много раз xor ah,[edi] ; res ^= *buf scasb ; ETX ?= *buf++ je endfor ; если == -> конец xor ah,[edi] ; res ^= *buf scasb ; ETX ?= *buf++ je endfor ; если == -> конец xor ah,[edi] ; res ^= *buf scasb ; ETX ?= *buf++ jne startfor ; если != -> продолжаем endfor: mov al,ah mov [edi],ah ; *buf = res pop edi ; или mov edi,edx ret LRC endp Инструкции xchg, scasb и т.п. Можно предположить, что Intel и AMD и далее будут совершенствовать свою продукцию, и тогда в следующих поколениях процессоров (а может и в P4) xchg и scasb уже не будут такими тормозными. Хотя в данном случае xchg находиться вне цикла, а использование scasb вроде как ускоряет процесс... |
|
|
Дата: Апр 27, 2003 07:02:50 boozook по-моему процессоры начиная с PPro обрабатывают 3 инструкции за такт Таких тонкостей я учитываю. Однако bcc v5.5 с опцией оптимизации по скорости и для PPro генерирует код с CMP + INC. Надо было сразу предложить автору темы сгенерировать ASM-код при помощи Си'шного компилятора. Про лишний SCASB я имел ввиду, что пару scasb ; ETX ?= *buf++ je endfor ; если == -> конец заменить на jmp short @@_на_второй_scasb Подозреваю, что макрос proc всегда генерит ... Afaik если использовать расширения USES, LOCAL, параметры, указывать язык и соглашения по вызову, то да, иначе нет. |
|
|
Дата: Апр 27, 2003 11:21:39 Можно ведь это скомпилить и дизассемблировать... |
|
|
Дата: Апр 27, 2003 21:49:01 · Поправил: boozook P2M bcc v5.5 с опцией оптимизации по скорости и для PPro генерирует код с CMP + INC. А он учитывает все тонкости архитектуры этих процессоров? Я не уверен. Если компилятор MSVC++ перевод числа с плавающей запятой в целое у меня скомпилировал так: fld qword ptr [eax] call _ftol ; функция из библиотеки MSVCRT32.DLL ;результат в eax если использовать расширения USES, LOCAL, параметры, указывать язык и соглашения по вызову я это и имел ввиду. Imho сложно написать такую процедуру, в которой все это необходимо. Если только в цикле что-нибудь в стэк загонять spaces Можно ведь это скомпилить и дизассемблировать... [C] Агнер Фог, пер. Aquila ... рекомендуется, чтобы компилятор умел переводить высокоуровневый код напрямую в ассемблер. Это даст вам гарантию, что вы получите верный метод вызова функции. Большинство компиляторов C++ умеют это делать ... ; int square (int x); SQUARE_I PROC NEAR ; целочисленная функция вычисления квадратного корня @square$qi LABEL NEAR ; имя, создаваемое компилятором Borland ?square@@YAHH@Z LABEL NEAR ; имя, создаваемое компилятором Microsoft _square__Fi LABEL NEAR ; имя, создаваемое компилятором Gnu PUBLIC @square$qi, ?square@@YAHH@Z, _square__Fi MOV EAX, [ESP+4] IMUL EAX RET SQUARE_I ENDP ; double square (double x); SQUARE_D PROC NEAR ; функция вычисления квадратного корня с двойной точностью @square$qd LABEL NEAR ; имя, создаваемое компилятором Borland ?square@@YANN@Z LABEL NEAR ; имя, создаваемое компилятором Microsoft _square__Fd LABEL NEAR ; имя, создаваемое компилятором Gnu PUBLIC @square$qd, ?square@@YANN@Z, _square__Fd FLD QWORD PTR [ESP+4] FMUL ST(0), ST(0) RET SQUARE_D ENDP Хех, я лучше сам переведу :) |
|
Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.037 |