· Начало · Отвђтить · Статистика · Поиск · FAQ · Правила · Установки · Язык · Выход · WASM.RU · Noir.Ru ·

 WASM Phorum —› WASM.A&O —› экономия регистра

. 1 . 2 . >>

Посл.отвђт Сообщенiе


Дата: Июл 19, 2004 23:23:53

Часто встречается(в т.ч. и на форуме) такие диалоги:
-"...экономим 1 регистр..."
-"...зато твой код длиннее на n байт...".
Объясните, плиз что даёт экономия регистра, и что зависит от количества задействованных регистров?


Дата: Июл 20, 2004 00:11:28

Смотря какой регистр
1) даёт возможность не сохранять его
2) можно использовать его под другие цели
3) просто кайф от победы над кодом


Дата: Июл 20, 2004 00:33:51 · Поправил: cresta

Т.е. выгода (в плане скорости или размера) может быть только в случае возникновения нехватки регистров(eax,ebx,ecx,edx) и связанной с этим необходимостью дополнительных пересылок в память(или стек) и обратно? А в остальных случая остаётся только кайф?


Дата: Июл 20, 2004 01:15:36 · Поправил: S_T_A_S_

У процессора есть всего 8 регистров общего назначения.
Один (ESP) занят под указатель на стек, так что в большенстве случаев непосредственно не используется.
Как правило, ещё и EBP отводят как указатель на стековый кадр - локальные переменные в ф-циях.
(Хотя последнее, в общем-то не обязательно делать, к ним можно и через ESP обращаться, но каждая команда тогда длиннее на байт будет)
Итого остаётся 6 регистров, в них уже можно хранить что угодно.
(хотя обычно есть некоторая специализация)

Так вот, к вопросу :)
Любая программа оперирует с различными данными.
Эти данные могут находиться в памяти, но в этом случае доступ к ним происходит довольно медленно.
К тому же, некоторые операции возможны только над данными находящимися в регистрах.
Поэтому данные, к которым в данный момент требуется максимально быстрый доступ, хранят в регистрах.

Теперь предположим, для какой-то операции желательно 8 регистров.
Как быть? Приходится один или 2 постоянно сохранять на стеке или ещё где - это сильно замедляет код.
Если же код переписать таким образом, что будет нужно 5 регистров, то выполнение ускорится. иногда очень сильно.
В общем-то, это основа оптимизации кода по скорости - как можно меньше использовать ОЗУ, стараться все вычисления делать в регистрах.

Если кажется, что остаётся только кайф, то можно ещё для каких-то целей использовать регистр.


Дата: Июл 20, 2004 02:47:40 · Поправил: cresta

S_T_A_S_
Т.е. как я понял, желательно смещать баланс хранения данных "память-регисты" в сторону регистров.
„Так вот, к вопросу :)“
Ну тогда, пока народ не очень сердитый (и не отсылает в поиск),ещё один вопрос: В электронной версии Юрова (других у меня просто нет :(() нет ничего о такой простой вещи: jmp на произвольный адрес. Несколько раз мне требовалось пререйти в другую процудуру, причем не на начало, а в середину, и я делал так:
;===========================================
FirstProc proc param1:DWORD,param2:DWORD
    ;
    ;здесь какой-то код
    ;
    mov jmpVar,1        ;переменная для проверки
    push eax
    push edx
    Call SomeProc
    ;
FirstProc endp
;==================================
SomeProc proc param1:DWORD,param2:DWORD
    cmp jmpVar,1        ;проверка, откуда мы пришли
    je @SomeLabel       ;если из FirstProc,то на @SomeLabel
    ;
    ;пропускаемый в данном случае кусок процедуры
    ;
    @SomeLabel:
    mov jmpVar,0        ;обнуляем переменную
    ;
    ;
SomeProc endp
;=================================================
Как можно заменить такую конструкцию на jmp<адрес метки @SomeLabel>или Call <адрес @SomeLabel> ? Наверное должен быть способ покрасивее.


Дата: Июл 20, 2004 03:48:24

cresta
Для того, чтобы можно было прыгнуть внутрь процедуры на какую-либо метку в ее теле, эта метка должна быть объявлена как глобальная, например (MASM32):

;===========================================
FirstProc proc param1:DWORD,param2:DWORD
;
;здесь какой-то код
;
Call @SomeLabel
;
FirstProc endp
;==================================
SomeProc proc param1:DWORD,param2:DWORD
;
;пропускаемый в данном случае кусок процедуры
;
@SomeLabel::
;
;
SomeProc endp
;=================================================


Дата: Июл 20, 2004 07:22:38

Прыгать внутрь процедуры немного рискованно - можешь пропустить какой-то кусок, который важен для выхода из процедуры. В таких случаях лучше пересмотреть логику программы и сделать пару функций, которые сделают код читаемым, но длинее на пару байт...

Хотя это, конечно, кто как... персональная установка.


Дата: Июл 20, 2004 09:36:52

это чисто дзенский изврат, современные процы, точнее их быстродействие от этого ничего не теряют


Дата: Июл 20, 2004 09:37:32

а вот если какие нить пик контролеры програмить, то тут данное умение будет даже очень кстати


Дата: Июл 20, 2004 14:00:47

Oleg_SK
„@SomeLabel::“
Двух двоеточий достаточно для глобального объявления, я так понял. Спасибо.
CARDINAL
Да это от ВЕ49 осталось, там вечно не хватало памяти и приходилось так извращаться. Сейчас необходимости нет, просто вижу, что кусок кода уже есть, не хочется писать его снова. Прыгнул и всё.


Дата: Июл 20, 2004 14:08:45 · Поправил: S_T_A_S_

cresta > „Т.е. как я понял, желательно смещать баланс хранения данных "память-регисты" в сторону регистров.“

В общем-то, да. Вобще-то я щас почитал, что написал раньше на сон грядущий.. Гхм.
Вроде такая простая IMHO вещь, а а сложно объяснить..
Я как учился: процессор - это отдельный блок, регистры находятся внутри, а память - снаружи.
Поэтому мне кажется совершенно логичным использовать (внешнюю) память только когда это действительно нужно.


> „Несколько раз мне требовалось пререйти в другую процудуру, причем не на начало, а в середину, и я делал так:“

IMHO в данном случае - это есдинственное решение (не меняя SomeProc proc)
Вариант, предложенный Oleg_SK работать не будет (хотя про глобальные метки верно),
т.к. при входе в середину SomeProc не будет происходить формирование стекового фрейма, зато он будет очищаться при выходе.
Нарушение баланса стека гарантированно.
Хотя, если SomeProc не имеет локальных переменных, то так делать можно.
В общем, зависит как определены option prologue и option epilogue.
Дело в том, что ret в MASM может произвести больше кода, чем C3h

Можно попробовать так:
;===========================================
FirstProc proc param1:DWORD,param2:DWORD
;
;здесь какой-то код
;
Call @SomeLabel
;
FirstProc endp
;==================================

SomeProc2 proc param1:DWORD,param2:DWORD
; здесь формируется стековый кадр, аналогичный SomeProc 
jmp @SomeLabel
SomeProc endp

SomeProc proc param1:DWORD,param2:DWORD
;
;пропускаемый в данном случае кусок процедуры
;
@SomeLabel::
;
;
ret ; здесь стековый кадр очищается
SomeProc endp
;=================================================



> „это от ВЕ49 осталось..“

Эта та штука, что была до МК 62 ? :)


Дата: Июл 20, 2004 15:15:15

S_T_A_S_
> Дело в том, что ret в MASM может произвести больше кода, чем C3h

А причем тут masm? ;-)
ret с коррекцией стека будет точно такой же что и в fasm ;-)


Дата: Июл 20, 2004 19:51:51

Asterix > „А причем тут masm? ;-) “

Есть такая штука, включенная по умолчанию:
option prologue:PrologueDef
option epilogue:EpilogueDef
Это значит, что не только ret n быдет, но ещё и pop ebp и add esp,XX врозможен


Дата: Июл 20, 2004 20:02:30

S_T_A_S_
В крайнем случае можно использовать retn, но оччень осторожно :-)


Дата: Июл 20, 2004 21:45:39 · Поправил: cresta

S_T_A_S_
„Нарушение баланса стека гарантированно.
Хотя, если SomeProc не имеет локальных переменных, то так делать можно. “

Во всех процедурах, куда пробовал втыкать @SomeLabel:: есть локальные переменные.
Если Call @SomeLabel, то в некоторых случаях (обычно callback) возвращается нормально. А иногда программа вылетает. Почему вылетает не всегда - не знаю.
А вот тут я ещё поизвращался: И помоему работает надёжно
;===========================================
FirstProc proc param1:DWORD,param2:DWORD
    ;
    ;здесь какой-то код
    ;
    push 0               ;из нулевого адреса вызываться
    jmp @SomeLabel       ;функция, содержащая @SomeLabel
    @Return::            ;никак не может
    ;
FirstProc endp
;==================================
SomeProc proc param1:DWORD,param2:DWORD
    ;
    ;пропускаемый в данном случае кусок процедуры
    ;
    @SomeLabel::
    ;
    ;
    pop eax        ;непосредственно перед ret проверяем
    test eax,eax   ;куда возвращаемся
    jnz @F         ;если нулевой адрес, значит уходим как и пришли -
    jmp @Return    ;через jmp
    @@:
    push eax       ;если не ноль - был нормальный вызов процедуры  
    ret
SomeProc endp
;=================================================

Причем через push 0 или push 1 или push 2 можно конкретно определить откуда пришли и определённо возвращаться в то же место.Т.е. push 0 (@Return0) в одном месте push 1 (@Return1) в другом и т.д.

„Эта та штука, что была до МК 62 ? :)“
Если речь о калькуляторах - то нет. Были такие однокристальные ЭВМ по моему серии КР 1816. Там была встроенная ПЗУ на 1024 байт. И туда надо было запихать ну очень много...

. 1 . 2 . >>


Powered by miniBB 1.6 © 2001-2002
Время загрузки страницы (сек.): 0.116