Andrew

« Hash Algorithm Attacks | Main | Breaking SuperFastHash (and chipping lookup3) »

MSVC rolls over

Posted on March 22, 2007 12:44 AM

If you are using MSVC7 or earlier and you want to rotate some uints, you'll be unpleasantly surprised when

#define rotl(x,k) (((x)<<(k)) | ((x)>>(32-(k))))

unsigned int test( unsigned int a, unsigned int b, unsigned int c ) {
	a -= c;  a ^= rotl(c, 4);  c += b;
	b -= a;  b ^= rotl(a, 6);  a += c;
	c -= b;  c ^= rotl(b, 8);  b += a;
	a -= c;  a ^= rotl(c,16);  c += b;
	b -= a;  b ^= rotl(a,19);  a += c;
	c -= b;  c ^= rotl(b, 4);  b += a;

	return ( c );
}

compiles to code that looks like:

  mov edi,eax
  shl edi,6
  shr ecx,1A
  or ecx,edi
  xor ecx,edx
  add eax,esi
  sub esi,ecx
  mov edx,ecx
  mov edi,ecx
  shl edi,8
  shr edx,18
  or edx,edi
  xor edx,esi

No! Bad dog! Unlike gcc and icc, MSVC7 and earlier don't like to recognize rol's / ror's when they see one and will instead generate dreadful shifts; this obviously slows your code down a bit, especially if it's in a tight innerloop.

The solution to the problem is to use _rotl (or _rotr), which Microsoft compilers implicitly generate rol / ror for. If you define your macros as _rotl / _rotr, you can do something like

#if !defined(_MSC_VER)
	#define _rotl(x,k) (((x)<<(k)) | ((x)>>(32-(k))))
#endif

and let the macro fall through to the built-in functions on Microsoft compilers. MSVC7 and earlier will now generate rotates properly:

  rol ecx,6
  xor ecx,edx
  add eax,esi
  sub esi,ecx
  mov edx,ecx
  rol edx,8
  xor edx,esi

TrackBack Info

TrackBack URL for this entry:
http://www.team5150.com/~andrew/blog/trackback.cgi/6

Post a comment

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)