Duff's Device It looks weird and wtf is even going on
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);
}
}
First: What Problem Is Duff’s Device Solving?¶
Suppose you want to copy count values from one array to another:
Simple.
But on older hardware:
- loop overhead was expensive
- branches were expensive
- CPUs were slow
So programmers used loop unrolling.
Instead of copying 1 item per iteration:
you copy several at once:
while (count >= 8) { *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; *to++ = *from++; count -= 8;}
Now the loop branch happens once every 8 copies instead of every copy.
That’s the basic idea.
The Remaining Problem¶
What if the number isn't divisible by 8?
Example:
- count = 13
You can do:
- 8 copies in one full loop
- but now 5 remain
Normally you'd write cleanup code:
Duff’s Device merges:
- the unrolled loop
- and the cleanup logic
into one bizarre structure.
Key Insight #1 — case Labels Are Just Labels¶
People imagine:
creates some special structure.
It mostly doesn’t.
A case label is basically:
- a jump target
- attached to a statement
That’s why this is legal:
No braces required.
And labels can exist inside nested blocks.
Key Insight #2 — Fallthrough Is Legal¶
Normally:
If x == 1, execution continues into case 2.
No automatic stopping occurs.
C switch statements are basically:
computed goto + labels + optional breaks
Key Insight #3 — do/while Executes First, Checks Later¶
A do/while loop:
always runs the body at least once.
This becomes crucial.
Now Let’s Trace It Slowly¶
Suppose:
Step 1 — Calculate Number Of Loop Iterations¶
Why?
Integer division rounds down.
So:
Meaning:
- we need 2 iterations
- each can copy up to 8 values
Step 2 — Determine Entry Point¶
So execution jumps to:
NOT the top.
This is the horrifying part.
Execution enters the middle of the loop body.
Step 3 — First Iteration Begins Midway¶
We jump directly here:
case 5: *to = *from++;case 4: *to = *from++;case 3: *to = *from++;case 2: *to = *from++;case 1: *to = *from++;
How many copies happened?
Cases:
- 5
- 4
- 3
- 2
- 1
Total:
Perfect.
That handles the leftover remainder.
Step 4 — Reach Bottom Of Loop¶
Now we hit:
Currently:
After decrement:
Condition true.
Loop continues.
Step 5 — Second Iteration Starts At TOP¶
This is the clever bit.
The second iteration does NOT re-enter via the switch.
The switch already happened.
Now control loops normally to the top of the do.
So execution begins here:
case 0: *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++;
Since there are no breaks:
- all 8 execute
Total:
Total Accounting¶
First partial iteration:
Second full iteration:
Total:
Exactly correct.
The Mental Model¶
Duff’s Device works by:
- entering an unrolled loop halfway through
- finishing the partial chunk
- looping normally afterward
It combines:
- remainder handling
- full loop processing
into one control structure.
Why This Is Legal¶
Because C allows:
- labels inside blocks
- switch labels attached to arbitrary statements
- fallthrough
- looping around labels
Nothing in the standard forbids:
- jumping into the middle of a loop body
So this monstrous thing is valid.
What The Compiler Sees¶
Conceptually something like:
if remainder == 5: goto LABEL5LOOP_TOP: copyLABEL7: copyLABEL6: copyLABEL5: copyLABEL4: copyLABEL3: copyLABEL2: copyLABEL1: copyif (--n > 0) goto LOOP_TOP
Once viewed this way, it becomes much less magical.
It’s basically hand-written control flow manipulation.
Why It Was Famous¶
Duff’s Device became legendary because it revealed:
- how permissive C’s control flow really is
- how deeply programmers understood machine costs
- how “high-level language” abstractions could be bent
It feels like:
- switch abuse
- goto abuse
- loop abuse
all simultaneously.
And yet:
- elegant
- efficient
- fully legal
Which is peak C.