Войти в систему

Home
    - Создать дневник
    - Написать в дневник
       - Подробный режим

LJ.Rossia.org
    - Новости сайта
    - Общие настройки
    - Sitemap
    - Оплата
    - ljr-fif

Редактировать...
    - Настройки
    - Список друзей
    - Дневник
    - Картинки
    - Пароль
    - Вид дневника

Сообщества

Настроить S2

Помощь
    - Забыли пароль?
    - FAQ
    - Тех. поддержка



Пишет qwerty ([info]qwerty)
@ 2006-09-11 23:27:00


Previous Entry  Add to memories!  Tell a Friend!  Next Entry
Размером кода озабоченным программистам
Есть такой мало известный способ неявной передачи параметров в небыструю подпрограмму - извлечь места их расположения из инструкций вокруг места вызова. Применять по мере надобности в сочетании с частично параметризованными переходниками.


(Добавить комментарий)


[info]furia-krucha.livejournal.com
2006-09-13 14:22 (ссылка)
Так передавала параметры EMT команда на PDP11, там ещё надо адрес возврата на стеке менять, чтобы не вернуться в данные.

(Ответить) (Ветвь дискуссии)


[info]qwerty
2006-09-13 14:35 (ссылка)
Нет, это совсем другой способ. Для него не нужно класть литералов вслед за инструкцией вызова, как это делалось на PDP-11 и в некоторых реализациях Фортрана. Но вполне полезные инструкции вокруг вызова должны следовать некоторым разумным правилам. Вызываемая подпрограмма знает эти правила, смотрит на инструкции и видит, откуда брать аргументы и куда класть результат. Очень хорошо сочетается с инструкцией условного вызова, в отличие от упомянутого вами способа.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]furia-krucha.livejournal.com
2006-09-13 14:43 (ссылка)
Гм... не понятно. Под "полезными инструкции вокруг вызова" имеются в виду инструкции которые (например) кладут параметры на стек и вынимают оттуда результат? Но если они есть то параметры уже на стеке и проще взять их оттуда.

(Ответить) (Уровень выше) (Ветвь дискуссии)


[info]qwerty
2006-09-13 23:09 (ссылка)
Прелесть именно в том, что этого делать не нужно.
Я этот способ применяю, когда имеется простой и короткий вариант некоторого действа, который должен быть максимально эффективен, но не покрывает некоторых редко возникающих ситуаций, и медленный и длинный вариант, который обрабатывает все, существует большое количество вхождений действа в коде, и при всем этом нужно заботиться о размере кода. Если б о нем не нужно было заботиться. все было бы просто: проверил, не возникло ли ситуации, ушел условным переходом на код для вызова медленного варианта, в этом коде сохранил все, что нужно, передал параметрами все, что нужно, вызвал, переместил результат, восстановил, вернулся на место после действа. И так в каждом вхождении. При применении же способа во вхождении остаются лишь проверка и условный вызов, все остальное производится медленной подпрограммой.

Пример 1. Допустим, какой-нибудь модный язык программирования очень часто отводит память в куче, производительность языка заметно зависит от скорости отведения, и при этом некий умник жаждет иметь этот язык реализованным для мелкого встроенного устройства. Длпустим, память отводится путем простого перемещения указателя в буфере, если буфер кончается, то вызывается сборщик мусора, который освобождает и уплотняет. Соответственно, код для бстрого отведения выглядит примерно так:
    ...
    load   pos_reg, [pos]              ; Возможно, не локально
    ...
    load   limit_reg, [limit]          ; Возможно, не локально
    ...
    add    tmp_reg, pos_reg, #size     ; Размер здесь может быть и не константой
    cmp    tmp_reg, limit_reg
    call_when_higher slow_allocator
    ...
    store  pos_reg, [pos]              ; Возможно, не локально

Нелокальность загрузок и сохранений может быть результатов вынесения общих подвыражений - загрузок вверх, сохранений вниз. Регистры повсюду такие, какие удобны компиляторному бэкенду для пущей эффективности быстрого отведения. Если прописать фиксированные, ему пришлось бы их туда-сюда гонять меж ними значения. Медленному обработчику нужно лишь найти инструкцию продвижения указателя
    add    tmp_reg, pos_reg, #size
и извлечь из нее все регистры. Для этого эта инструкция должна быть расположена в ожидаемом месте - например, должна быть последней инструкцией типа add из небольшого числа инструкций перед вызовом. Проще всего было бы потребовать фиксированного расстояния, но реальная жизнь сложнее.

Пример 2. Допустим, у некоторого процессора плавающая точка кривовата - стандарт IEEE754 почти, но не совсем выдержан (в некоторых необычных ситуациях результат не стандартен, и процессор в этих случаях выставляет флажок), а язык программирования требует строгого подчинения стандарту. Поступаем примерно так же, потребовав лишь, чтобы кодогенератор в сомнительных случаях не записывал результат ни в один из операндов и вставлял условный вызов программной симуляции плавающей точки по флажку. Опять-таки, в реальной жизни все несколько сложнее.

(Ответить) (Уровень выше)