Welcome to MSDN Blogs Sign in | Join | Help

C#: PG required, obscene case fall through code and Duff device

I had said before that I miss case fall through in C# and I promised that I'd write about some weird uses of this feature in C++. 

I think the weirdest use of case statement was made by Tom Duff. He needed to write some code in C that copied an array of shorts into a pre-programmed IO data register. The code looked like

void loopSend(register short* to, register short* from, register int count)

{

do

*to = *from++;

while(--count > 0);

}

The compiler emitted instructions to compare the count with zero after each copying each short. This had a considerable perf hit and so he decided to apply common loop unrolling technique. This is where things became extremely weird. He used a little-known C feature in which switch-case statements can be inter-leaved with other statements. The optimized code looked like

void send(register short *to, register short *from, register int count)

{

register int 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);

}

}

If you are wondering if its legal C, then think again, as this is not only legal C, it's legal C++ as well. If you change all *to to *to++ this becomes a memcpy code which is more relevant to most programmers. When I first saw this is college, I had to actually step through the code to figure out how it worked and then kept wondering why there was no obscene code warning before the code and so I made it a point to add it in the blog title :)

Some people took this to the extreme and created a stack based co-routine. People who take yield return for granted should try understanding the following

#define crBegin static int state=0; switch(state) { case 0:

#define yieldReturn(i,x) do { state=i; return x; case i:; } while (0)

#define crFinish }

int function(void) {

static int i;

crBegin;

for (i = 0; i < 10; i++)

yieldReturn(1, i);

crFinish;

}

 

Published Wednesday, November 23, 2005 7:20 PM by abhinaba
Filed under:

Comment Notification

If you would like to receive an email when updates are made to this post, please register here

Subscribe to this post's comments using RSS

Comments

# re: C#: PG required, obscene case fall through code and Duff device

Wednesday, November 23, 2005 11:00 AM by Evin
I'm afraid this won't compile in C. case labels require a constant. Nice try, though.

# re: C#: PG required, obscene case fall through code and Duff device

Wednesday, November 23, 2005 3:22 PM by Manip
Worst code ever. That is over-optimised and un-maintainable. I'd prefer a slow solution to THAT solution. :-|

# re: C#: PG required, obscene case fall through code and Duff device

Wednesday, November 23, 2005 4:24 PM by kfarmer
Fiendish.. I like it in a masochistic sorta way.

Evin: re-read.. it would appear that some compiler out there doesn't mind that code.

Manip: True, but that's not why that code was created, wasn't it? Would you want the slow code in something that *must* be high performance? That's a trade-off that must be learned.

# re: C#: PG required, obscene case fall through code and Duff device

Thursday, November 24, 2005 12:17 AM by abhinaba
Evin I said the first sample (Duff device) is legal C. The coroutine is C++.

# re: C#: PG required, obscene case fall through code and Duff device

Thursday, November 24, 2005 12:21 AM by abhinaba
Manip what kfarmer highlights is absolutely true. The original Duff device was coded to handle a bottle neck that was slowing down an animation payback. If some situation you just cannot do without such things. Since I was an embedded system programmer for some time, I wrote lots of code that used loop un-rolling to speed up that MP3 ringtone play-back on your cell phone :)

# re: C#: PG required, obscene case fall through code and Duff device

Thursday, November 24, 2005 6:31 AM by Random Reader
The case label _is_ constant -- it's a preprocessor substitution, not a source variable.

Google has Tom Duff's original post archived, FWIW:
http://groups.google.com/group/net.lang.c/msg/66008138e07aa94c

Leave a Comment

(required) 
required 
(required) 
 
Page view tracker