This is correct, and someone aware of these issues could have circumvented them easily. Nevertheless i assume it works on any platform with two's complement integer representation, which encompasses ARM and Intel processors. The point here is the difference between "undefined behaviour" and "implementation defined behaviour".
The real issue here is the abuse of the union and this _is_ serious "undefined behaviour". It is a common anti pattern, which happens to work on older, less optimizing compilers.
couple of questions about stockfish code ?
Moderator: Ras
-
BeyondCritics
- Posts: 415
- Joined: Sat May 05, 2012 2:48 pm
- Full name: Oliver Roese
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
The use of a union is actually the right way to do this without introducing undefined behaviour (as opposed to recasting pointers, violating aliasing rules).BeyondCritics wrote:This is correct, and someone aware of these issues could have circumvented them easily. Nevertheless i assume it works on any platform with two's complement integer representation, which encompasses ARM and Intel processors. The point here is the difference between "undefined behaviour" and "implementation defined behaviour".
The real issue here is the abuse of the union and this _is_ serious "undefined behaviour". It is a common anti pattern, which happens to work on older, less optimizing compilers.
The use of a union to map, in this case, between two 16-bits ints and one 32-bit int is not "undefined behaviour" but again "implementation-defined behaviour".
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
Hmm, it is certainly perfectly legal in C99 and C11.syzygy wrote:The use of a union is actually the right way to do this without introducing undefined behaviour (as opposed to recasting pointers, violating aliasing rules).BeyondCritics wrote:This is correct, and someone aware of these issues could have circumvented them easily. Nevertheless i assume it works on any platform with two's complement integer representation, which encompasses ARM and Intel processors. The point here is the difference between "undefined behaviour" and "implementation defined behaviour".
The real issue here is the abuse of the union and this _is_ serious "undefined behaviour". It is a common anti pattern, which happens to work on older, less optimizing compilers.
The use of a union to map, in this case, between two 16-bits ints and one 32-bit int is not "undefined behaviour" but again "implementation-defined behaviour".
In C++ it might be formally undefined, but at least g++ allows it as a language-extension. I'm sure Clang then does the same.
-
Sven
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: couple of questions about stockfish code ?
All that trouble would be avoided by using a struct of two 16-bit integers ... And the speed difference between "struct" and the current "sophisticated" version (if there is any speed difference at all) would be negligible and not relevant for strength. You have to consider more than just the effort for adding two 32-bit integers vs. twice adding two 16-bit integers, there is also the additional decoding effort in mg_value().syzygy wrote:Hmm, it is certainly perfectly legal in C99 and C11.syzygy wrote:The use of a union is actually the right way to do this without introducing undefined behaviour (as opposed to recasting pointers, violating aliasing rules).BeyondCritics wrote:This is correct, and someone aware of these issues could have circumvented them easily. Nevertheless i assume it works on any platform with two's complement integer representation, which encompasses ARM and Intel processors. The point here is the difference between "undefined behaviour" and "implementation defined behaviour".
The real issue here is the abuse of the union and this _is_ serious "undefined behaviour". It is a common anti pattern, which happens to work on older, less optimizing compilers.
The use of a union to map, in this case, between two 16-bits ints and one 32-bit int is not "undefined behaviour" but again "implementation-defined behaviour".
In C++ it might be formally undefined, but at least g++ allows it as a language-extension. I'm sure Clang then does the same.
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
Addition of score values is far more frequent than encoding/decoding. I'm pretty sure using a struct of two 16-bit ints would be measurably slower. Also because I have no doubt that if there were no speed penalty, Stockfish would already use the "simpler" approach. (And probably it started with such an implementation, but I have not looked into what very old versions did.)
Anyway, why are people getting excited about this?
Anyway, why are people getting excited about this?
-
Fulvio
- Posts: 399
- Joined: Fri Aug 12, 2016 8:43 pm
Re: couple of questions about stockfish code ?
Maybe you should read this:syzygy wrote:Addition of score values is far more frequent than encoding/decoding. I'm pretty sure using a struct of two 16-bit ints would be measurably slower.
https://en.wikipedia.org/wiki/Instructi ... arallelism
https://software.intel.com/en-us/blogs/ ... ndy-bridge
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
Or maybe you should just test and measure.Fulvio wrote:Maybe you should read this:syzygy wrote:Addition of score values is far more frequent than encoding/decoding. I'm pretty sure using a struct of two 16-bit ints would be measurably slower.
https://en.wikipedia.org/wiki/Instructi ... arallelism
https://software.intel.com/en-us/blogs/ ... ndy-bridge
Why do you think that using TWO registers to keep track of the aggregated score in evaluate() instead of just one incurs no performance penalty?
The only sensible alternative to the union approach that I see is wrapping the two 16-bit ints into one 32-bit int "by hand" using a shift and an OR/addition. This should in principle give more or less the same code (depending on the endianness of the platform). I assume it has been found out in the past that compilers did not handle this as efficiently (but I am no encyclopedia of Stockfish development... just answering a simple question that was posed here and being a little surprised with the shock and horror it is apparently causing).
-
BeyondCritics
- Posts: 415
- Joined: Sat May 05, 2012 2:48 pm
- Full name: Oliver Roese
Re: couple of questions about stockfish code ?
The right way to do this, is not to break (or burden, for that matter) the type system. This means here to use shift instructions. On any modern compiler you will get perfectly optimized code from that, without any hassles or concerns.syzygy wrote:...
The use of a union is actually the right way to do this without introducing undefined behaviour (as opposed to recasting pointers, violating aliasing rules).
...
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
This is actually what the new code is doing, and it uses a union only for converting between signed and unsigned 16-bits.syzygy wrote:The only sensible alternative to the union approach that I see is wrapping the two 16-bit ints into one 32-bit int "by hand" using a shift and an OR/addition. This should in principle give more or less the same code (depending on the endianness of the platform).
It seems to me this relies on implementation-defined behaviour as much as using straightforward casts. But I might be missing something here.
-
syzygy
- Posts: 5939
- Joined: Tue Feb 28, 2012 11:56 pm
Re: couple of questions about stockfish code ?
Well, I was reacting to your allegation of abuse and undefined behaviour. That may hold some truth for C++, it seems, but not for C99/C11 and not for C++ as "extended" by g++.BeyondCritics wrote:The right way to do this, is not to break (or burden, for that matter) the type system. This means here to use shift instructions. On any modern compiler you will get perfectly optimized code from that, without any hassles or concerns.syzygy wrote:...
The use of a union is actually the right way to do this without introducing undefined behaviour (as opposed to recasting pointers, violating aliasing rules).
...
I do agree that SF's current approach is to be preferred as it does not rely on endianness.