Using bitfields to store a move?

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

sluijten
Posts: 44
Joined: Wed Apr 13, 2011 12:43 pm

Using bitfields to store a move?

Post by sluijten »

Bitfields are not portable in C, i.e. the language does not define what the MSB and LSB will be. Is there a problem with that?
I want to use bitfields (UNION-ed with an unsigned integer) to store a move, and do not intend to do any masking or shifting on the fields.
I only need 24 bits, but intend to inflate this to 32-bit, so a move will be aligned with a 32-bit integer, which might be faster on some compilers/systems.
But still wonder if there might be reason for not using bitfields? any thoughts?

Code: Select all

union Move {
   struct {
      unsigned from          : 8;
      unsigned to            : 8;
      unsigned movingPiece   : 8;
      unsigned capturedPiece : 4;
      unsigned promoteTo     : 4;
   };
   unsigned int moveInt;
};
User avatar
sje
Posts: 4675
Joined: Mon Mar 13, 2006 7:43 pm

Re: Using bitfields to store a move?

Post by sje »

sluijten wrote:Bitfields are not portable in C, i.e. the language does not define what the MSB and LSB will be. Is there a problem with that?
Bitfields can be portable as long as no unsupported assumptions are made.

As the layout of a bitfield object is not specified in detail, there is no guarantee that a bitfield variable written in binary to a file can be properly read by anything other than a program compiled by the same compiler and running on the same platform with the same libraries.

Also, bitfield access can be slower than explicit masking and shifting.
sluijten
Posts: 44
Joined: Wed Apr 13, 2011 12:43 pm

Re: Using bitfields to store a move?

Post by sluijten »

sje wrote:Also, bitfield access can be slower than explicit masking and shifting.
Really? Should be easy to measure a difference with perft.
Could bitfield performance also be faster than masking & shifting?
Or is masking & shifting going to be the 'upper speed limit' ?
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Using bitfields to store a move?

Post by bob »

sluijten wrote:Bitfields are not portable in C, i.e. the language does not define what the MSB and LSB will be. Is there a problem with that?
I want to use bitfields (UNION-ed with an unsigned integer) to store a move, and do not intend to do any masking or shifting on the fields.
I only need 24 bits, but intend to inflate this to 32-bit, so a move will be aligned with a 32-bit integer, which might be faster on some compilers/systems.
But still wonder if there might be reason for not using bitfields? any thoughts?

Code: Select all

union Move {
   struct {
      unsigned from          : 8;
      unsigned to            : 8;
      unsigned movingPiece   : 8;
      unsigned capturedPiece : 4;
      unsigned promoteTo     : 4;
   };
   unsigned int moveInt;
};
It can be a problem if you want to dump the excess 0 bits to save space in the hash for best move, as an example. But even worse, performance is terrible. Much easier to and/or and do the packing/unpacking yourself...
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Using bitfields to store a move?

Post by bob »

sluijten wrote:
sje wrote:Also, bitfield access can be slower than explicit masking and shifting.
Really? Should be easy to measure a difference with perft.
Could bitfield performance also be faster than masking & shifting?
Or is masking & shifting going to be the 'upper speed limit' ?
masking/shifting is significantly faster than bitfields. You can test to confirm. Most of us have, and gave up due to performance issues...
wgarvin
Posts: 838
Joined: Thu Jul 05, 2007 5:03 pm
Location: British Columbia, Canada

Re: Using bitfields to store a move?

Post by wgarvin »

sluijten wrote:
sje wrote:Also, bitfield access can be slower than explicit masking and shifting.
Really? Should be easy to measure a difference with perft.
Could bitfield performance also be faster than masking & shifting?
Or is masking & shifting going to be the 'upper speed limit' ?
Compiler writers don't usually put a lot of effort into the treatment of bitfields. Lots of compilers generate crappy code for them. So you will probably get faster code if you write the masking and shifting yourself.

You should also do the masking and shifting yourself if the placement of the bitfields matters, if you want them in a certain order within the word so you can sort by the whole word. If you don't care about those things then using bitfields can help you have nice readable code.

If you go with bitfields, there are some things to be careful about:

* Try to use a type large enough to contain all of your bitfields so that it doesn't have to insert padding bits between bitfields. If the type you use is too small it will waste padding bits rather than trying to split the field in two parts.

* Use an unsigned type. If you just use something like "int" you may get some nasty surprises.

* Single-bit fields work nicely as flags or bool replacements. You can write inline setter and getter methods that cast to and from the "proper" type for what you want to store (bool, an enum, etc.). Putting your bitfields into a struct inside a union with a regular integer-typed field can also be handy (you can use that member for things like copy constructors). It might make them more annoying to initialize though.

* Don't assume your compiler is smart enough to merge a bunch of assignments of literal values to the bitfields into a single assignment to the underlying type. If you have any code like that where you care about the performance (e.g. if you assign them all in the constructor, and you're constructing an array of 1000 of them) then you should check the generated code to make sure its not too stupid.
mar
Posts: 2554
Joined: Fri Nov 26, 2010 2:00 pm
Location: Czech Republic
Full name: Martin Sedlak

Re: Using bitfields to store a move?

Post by mar »

sluijten wrote:Bitfields are not portable in C, i.e. the language does not define what the MSB and LSB will be. Is there a problem with that?
I want to use bitfields (UNION-ed with an unsigned integer) to store a move, and do not intend to do any masking or shifting on the fields.
I only need 24 bits, but intend to inflate this to 32-bit, so a move will be aligned with a 32-bit integer, which might be faster on some compilers/systems.
But still wonder if there might be reason for not using bitfields? any thoughts?

Code: Select all

union Move {
   struct {
      unsigned from          : 8;
      unsigned to            : 8;
      unsigned movingPiece   : 8;
      unsigned capturedPiece : 4;
      unsigned promoteTo     : 4;
   };
   unsigned int moveInt;
};
I tried using bitfields in my previous engine, it's comfortable for the programmer but the performance was a problem so I recommend not to do that and do the masking/shifting yourself instead. Besides, you don't know how the compiler packs the fields. Alternatively you can use
unsigned char from, to and unsigned short flags. Hope that helps.

Regards
Martin
Mincho Georgiev
Posts: 454
Joined: Sat Apr 04, 2009 6:44 pm
Location: Bulgaria

Re: Using bitfields to store a move?

Post by Mincho Georgiev »

I don't understand. In the above structure, the maximum size of your move is integer. So why using bit-fields instead of 4 bytes in the unnamed tag. That is exactly what I use in Pawny. It's simpler than bit shifting. Because of the unnamed tag doesn't add a struct ref. (Move.from instead of Move.S.from) and you simply have a byte ptr[x] reference to extract member data. Of course it's changing the usage that way - you will have stored square numbers and packed integer to transfer or compare, so it's up to you to decide whether is working for you. Plus if you do scoring in the packed my comment is irrelevant, but looking at your structure that doesn't seems to be the case.