This is almost the same as Duff's code without the switch statement. It's a simple unrolled loop that copies 8 words per iteration.
Next, consider how to handle a count that is not a multiple of 8. You could simply add a loop that copies a single word at a time, but to avoid the overhead of a loop, you could instead use a switch statement, making use of C's fallthrough behavior when omitting the break after each case:
switch (count%8) {
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++;
}
Now take a look at the actual Duff's device implementation line by line:
register n=(count+7)/8;
n is the number of iterations of the copy-8-words unrolled loop.
The +7 causes the division by 8 to round up in order to count the extra partial loop iteration required when count is not a multiple of 8.
switch(count%8){
count % 8 is the number of left-over words that need to be handled with a partial copy loop (rather than full 8-byte copy loops). The switch will jump to one of the following case labels in order to skip to a part of the unrolled copy loop such that exactly the number of left-over bytes will be copied.
case 0: do{ *to = *from++;
This is the first case of the switch, but also the beginning of the unrolled copy loop. If count happened to be a multiple of 8, then count % 8 would be 0, and the unrolled copy loop would begin executing as normal, identical to the simplified code above that only handles multiples of 8. Note that C's switch statement cases are essentially just labels; execution will fall through to the next case label unless a break is encountered, so after first entering the do{}while loop, the case statements are essentially ignored.
case 7: *to = *from++;
This line is where the real magic begins. If count % 8 was not 0, part of the first iteration of the unrolled loop will be skipped by jumping into the middle of the loop using the case label matching the number of extra words required. Then further iterations of the loop will continue as normal, copying the full 8 words per iteration.
The following case statements all serve the same purpose: to set up a label for a partial copy loop of the given number of words during the first iteration.
}while(--n>0);
This is the end of the unrolled copy loop. n, as calculated above, is the number of times to run the unrolled loop; remember that it included an extra iteration (due to rounding up) to account for the partial first iteration if count % 8 was not 0. When execution reaches this while, it will jump back up to the do (which happens to be in the middle of a switch, but that doesn't matter anymore - the case labels are ignored and the unrolled loop will now execute as normal, copying the full 8 words each iteration.
The magic is in reusing the same unrolled copy loop code to also do the initial partial copy.
Next, consider how to handle a count that is not a multiple of 8. You could simply add a loop that copies a single word at a time, but to avoid the overhead of a loop, you could instead use a switch statement, making use of C's fallthrough behavior when omitting the break after each case:
Now take a look at the actual Duff's device implementation line by line: n is the number of iterations of the copy-8-words unrolled loop. The +7 causes the division by 8 to round up in order to count the extra partial loop iteration required when count is not a multiple of 8. count % 8 is the number of left-over words that need to be handled with a partial copy loop (rather than full 8-byte copy loops). The switch will jump to one of the following case labels in order to skip to a part of the unrolled copy loop such that exactly the number of left-over bytes will be copied. This is the first case of the switch, but also the beginning of the unrolled copy loop. If count happened to be a multiple of 8, then count % 8 would be 0, and the unrolled copy loop would begin executing as normal, identical to the simplified code above that only handles multiples of 8. Note that C's switch statement cases are essentially just labels; execution will fall through to the next case label unless a break is encountered, so after first entering the do{}while loop, the case statements are essentially ignored. This line is where the real magic begins. If count % 8 was not 0, part of the first iteration of the unrolled loop will be skipped by jumping into the middle of the loop using the case label matching the number of extra words required. Then further iterations of the loop will continue as normal, copying the full 8 words per iteration.The following case statements all serve the same purpose: to set up a label for a partial copy loop of the given number of words during the first iteration.
This is the end of the unrolled copy loop. n, as calculated above, is the number of times to run the unrolled loop; remember that it included an extra iteration (due to rounding up) to account for the partial first iteration if count % 8 was not 0. When execution reaches this while, it will jump back up to the do (which happens to be in the middle of a switch, but that doesn't matter anymore - the case labels are ignored and the unrolled loop will now execute as normal, copying the full 8 words each iteration.The magic is in reusing the same unrolled copy loop code to also do the initial partial copy.