5 ms·
https://en.wikipedia.org/wiki/Duff%27s_device https://en.wikipedia.org/wiki/Duff%27s_device send(to, from, count) register short *to, *from; register cou
by _whiteCaps_ 4y ago
https://en.wikipedia.org/wiki/Duff%27s_device https://en.wikipedia.org/wiki/Duff%27s_device
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);
}
}
- vinay_ys 4y agoI encountered this technique and I learned the concept of coroutines, it was quite something.
- hansvm 4y agoI remember something about that too. Was this the blog you read? https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html https://www.chiark.greenend.org.uk/~sgtatham/coroutines.html
- rablackburn 4y agoThat was an excellent read. Thanks for sharing. Always love blog posts that cite Knuth.
- vinay_ys 4y agoHehe. yeah, exactly. And Putty was the ssh client I had used for a while on Windows.
- krylon 4y agoFor a long time, I would at this about once a year and almost understand what it does, but never quite getting it. It felt like looking at a hypercube. Then I read it was about loop unrolling, and suddenly it clicked.
- taneq 4y agoAnd also the fact that C sometimes cares way less than you might think about what goes where. :)
- krylon 4y agoAfterwards, I started to like Duff's description of his device as being a strong argument in the debate on switch's fallthrough behavior, but that he did not know if it was pro or con.
- null0pointer 4y agoAnother good example of this flexibility in C is the inverse array notation (I think that’s what it’s called, turns out it’s impossible to search because all the results are about reversing arrays). arr[index] is equivalent to index[arr] This works because arr points to the memory location of the zeroth index of the array and index is the offset from that memory location. Since addition is commutative so too is the array notation.
- justinsaccount 4y agoRight, arr[index] is sugar for *(arr+index) which is then also *(index+arr) and index[arr] edit: fixed escaped asterisks :-)
- jbverschoor 4y agoThat sounds soo dirty though
- krylon 4y agoIt is[0]. Duff's device, whether you like it or hate it, was a performance optimization at least, saying "idx[arr]" instead of "arr[idx]" does not help in any way and will make some people angry or sad. Contestants in the International Obfuscated C Code Contest will (and probably already have) find delightful ways to use and abuse this syntactical curiosity. [0] My one-track mind always wants to jump to pirate jokes. EDIT: If you like to explore this area, I highly recommend "Expert C Programming - Deep C Secrets" (get the pun? There's a fish on the cover...) by Peter Van Der Linden. It's pretty old (it talks about DOS memory models, among other things), but it is a fun deep dive into the murky corners of C. I wish there was an updated version and/or books covering other languages in that style.
- bjconlan 4y agoYeah the duffs device did it for me too. I remember reading it in some game programming book but shocked to see it used in qt/embedded for it's software rendering. This is up there for me or there's also that amazing recursive template class for n-dimentional vectorspaces written by Tim Sweeney. I can't find the page anymore but there is reference to it in the archive https://www.flipcode.com/archives/Unrolling_Loops_With_Meta-Programming.shtml https://www.flipcode.com/archives/Unrolling_Loops_With_Meta-...
- Arcuru 4y agoEverybody mentions this, and what's great is that it is a pretty natural solution to a lot of problems. I remember coming up with a version of it while writing an optimized prime-sieve[1], and was surprised when I later learned that it was some named technique. In addition to just the basic loop-unrolling (which I'm pretty sure you usually don't need to do by hand with modern compilers), it works really well when you need to jump into the middle of a pattern. Like if you're sieving primes in a wheel-factorized array. [1] https://github.com/patricksjackson/primes-cpp/blob/master/primes.cpp#L169-L179 https://github.com/patricksjackson/primes-cpp/blob/master/pr... // Here we're only checking possible primes after wheel-factorization switch ((p.second/num)%30) do { case 1: target->set(n); n+=num*6; case 7: target->set(n); n+=num*4; case 11: target->set(n); n+=num*2; case 13: target->set(n); n+=num*4; case 17: target->set(n); n+=num*2; case 19: target->set(n); n+=num*4; case 23: target->set(n); n+=num*6; case 29: target->set(n); n+=num*2; } while(n <= high - range.first);
- fractalb 4y agoShouldn’t it be *to++ = *from++;
- jcranmer 4y agoIn the original code, actually, no, incrementing "to" was not desired. The "to" was pointing to a hardware memory-mapped register, and it needed to copy to the same memory location each time.
- fractalb 4y agoDidn’t know that. Thanks
- johnthescott 4y agoamen. seems like back in the day that "reg1 = *pc++;" would have been the fastest op in a computer.