Sesse wrote: ↑
Mon Nov 26, 2018 10:18 pm
Two problems with this in Java:
- boolean is not implicitly convertible to int; you'll need b ? 1 : 0.
- Arrays are bounds-checked, which takes time (although the check may be optimized out)
I think the JIT might generate cmov or some other magic like that in case 1, perhaps even the frontend could optimize it (but not sure if Java bytecode has support for this, WebAssembly has "select" opcode I think).
Bounds checks are certainly a big problem in C# (I bet Java faces the same problems) due to the way arrays are represented. Typically extra pointer to "array object" with data and size members so that it can be GC-d and safe (+most likely no way to use references as class members because otherwise you couldn't track aliasing which can be hard problem in general, imagine you'd store reference to array[index] in a class, somewhere, I believe C# allows some sort of refs but only on stack).
There's no nice way to define static constant arrays in these languages which does't suck; even if you have say PST and the compiler might actually determine that you'll never index it out of bounds, it still generates the bounds check, because it's still technically something allocated on heap and GC-d later.
So it caches the object pointer in a register, but then does fetch size member via indirection anyway (doesn't even know the array has 64 elements even if it's
readonly or immutable or whatever).
I'm not sure it caches the array data pointer; but I don't remember seeing it cached (maybe that was some corner case I was looking at).
Sometimes the compiler is smart enough to move the bounds check outside of a loop, but in C# that implies that you iterate from 0 too array.length and they stll have a long way to go to improve this (for example, if you use backward iteration then it doesn't optimize this)
Indexing multi-dimensional arrays is even worse than that and the bounds check is generated all the time, one per dimension. I'm not sure Java does better here than C#.
The price to pay for safety, in C# you can't turn off bounds checking and I bet the same holds for Java.
Now compare that to C/C++ where indexing the static array itself is a single instruction which can be easily pipelined.
In C#, you might be able to work around this by using unsafe/fixed? and use pointers directly, if you could extract data pointer from array object somehow, which I'm not sure is possible.
Either way, I don't believe that bounds checking is the whole story why these managed languages perform so badly on chess engines, most likely their JIT compiler is not as good as fanboys claim (but they went a long way and can generate very good code if you don't need arrays).
For bitboard engines, I'm not sure there are intrinsics for bit scan/pop count (maybe there's is some way, I don't know).
Or maybe it's because AOT compilers can spend any time they like optimizing the code, they can optimize across compilation units and more.
Long story short: if you want maximum performance for your chess program, you don't want to use Java or C#.