Permalink
Switch branches/tags
Nothing to show
Find file Copy path
Fetching contributors…
Cannot retrieve contributors at this time
35 lines (29 sloc) 3.42 KB

title: "Устройство Даффа" lang: ru date: 17 Dec 2009 00:00:00 +0200 extends: default.liquid

Последнее время занимаюсь самосовершенствованием: пытаюсь постигнуть дао монад. Получается с переменным успехом: на интуитивом уровне вроде понял, но мне этого мало, хочу понять их устройство на более глубоком уровне, чтобы не просто их использовать, но и понимать, как они работают. А пока копался в доках на вики и прочих источниках, наткнулся на ссылку о «Duff's device».

Википедию прочитать, думаю, под силу каждому, но цель этого поста скорее зафиксировать полученное знание и понимание концепции мной самим, чтобы потом не забыть =)

Если кратко: устройство Даффа — это обобщение оптимизации циклов путём их развёртки. Проблема развёртки цикла с неизвестным числом повторов n в том, что при заданной глубине развёртки m существует n mod m «остаточных» итераций, которые надо обработать как особый случай. Дафф нашёл очень элегантное решение этой задачи на C:

send(to, from, count)
register short *to, *from;
register count;
{
    register n = (count + 7) / 8;
    switch (count % 8) {
    case 0: do { *to = *from++;
    case 7:      *to = *from++;
    case 6:      *to = *from++;
    case 5:      *to = *from++;
    case 4:      *to = *from++;
    case 3:      *to = *from++;
    case 2:      *to = *from++;
    case 1:      *to = *from++;
               } while (--n > 0);
    }
}

Как это работает: цикл из count повторов разворачивается на n равных кусков по 8 операций в каждом, а остаток операций в n mod 8 штук выполняется через switch: при первой проходе мы попадаем на один из case'ов в зависимости от этого остатка и сразу выполняем нужное остаточное число операций, а потом цикл while() работает своим обычным образом, пропуская все куски, на которые разбит исходный цикл.

За подробностями, почему так сделано и почему *to не инкрементируется — см. ссылки. Если кратко: to это не просто ссылка на адрес в памяти, а ссылка на адрес в IO-памяти, а цель всего кода — передать устройству с портом ввода-вывода по адресу to набора из count команд из памяти начиная с адреса from.