Very strange Bug

Discussion of chess software programming and technical issues.

Moderator: Ras

User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

Hello Adam,
adamh wrote:I suggest you rewrite all your attack functions to return unsigned __int64, because they do not despite what you originally wrote. In fact why not use unsigned __int64 everywhere?
i think the attackGetter functions are returning "unsigned __int64".
i think too, everyone knows what ui64_t is, especially because of my
introducing post.
adamh wrote: I think that would solve the problem, and my belief is reinforced by the fact the it seemed to work after HGMs suggestion with temp variables of that built-in type.
i have to dissapoint you, because HGMs suggestion also does not work.
i only stated that using the temp again in the mentioned codeblock
seems to work, at least i did not get any exception.

Further there is another workaround with explicit casting, but
here it is not the only thing to get it to work, but to understand
why such a behaviour can occur, although the input for the expression
is verified as ok.
adamh wrote:
I would be tempted to make a huge bet that this is not a compiler bug. A more probable explanation would be in the definition of the ui64_t type, It would be interesting if you want to provide that.
What you bet for, i hope for :wink:
i think meanwhile you know what ui64_t is. But you can
ask Gerd what U64 type is, which he used in his code
(dont take me too serious now :lol: ).
adamh wrote:
(Funny stuff could possibly occur in the possible argument promotion - and matching - in the call to the binary "&" operator)
sorry i cannot follow here.

regards
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

Hello Gerd,

first thx for your time you have spent on the topic.
i will keep in mind your optimization advises.

next...

Does this one behave same? Sometimes buggy compiler are quite sensible to some simple changes ...

static void genCastleCheck(pos_t *pos,mli_t *mli)
{
if (pos->cst & oow) {
U64 rookAttacks = attackR(KING(black),OCCUPIED);
if ( rookAttacks & bF1) {
generate_oow(pos,mli);
}
}
}
Unfortunatelly the same unexpected behaviour.
i will check out next, what the influence of the "__inline " stuff is, you
mentioned.

what is left now ? the only intransparent thing for all of you may be,
if the occupancy is ok, and the attackGetter really returns correct results
therefore. i have checked this out now for at least 30 times...
i cannot find any broken data.

Code: Select all

static void genCastleCheck(pos_t *pos,mli_t *mli)
{
 static int x;
 if((pos->cst & oow)  && (attackR(KING(black),OCCUPIED) & bF1)) 
 {
  fprintf(out,"\nattackR %I64u %d",attackR(KING(black),OCCUPIED) & bF1,++x);
  generate_oow(pos,mli);}
}
output ...

Code: Select all


...
attackR 32 9198
attackR 32 9199
attackR 32 9200
attackR 32 9201
attackR 32 9202
attackR 32 9203
attackR 32 9204
attackR 32 9205
attackR 32 9206
attackR 0 9207
attackR 0 9208
attackR 0 9209
attackR 0 9210
attackR 0 9211
attackR 0 9212
attackR 0 9213
attackR 0 9214
attackR 0 9215
...

:? normally it is impossible to get the output "0" here, or in other
words the output must always be 32...
:shock:

Michael
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

ok, just another information... (using intrinsics)

Code: Select all


static void genCastleCheck(pos_t *pos,mli_t *mli) 
{ 
  if (pos->cst & oow) 
  { 
   si64_t rookAttacks = attackR(KING(black),OCCUPIED); 
   //if( _bittest64(&rookAttacks,f1)) {generate_oow(pos,mli);} //    WORKING see assembly 1
   if(rookAttacks & bF1) {generate_oow(pos,mli);}              //NOT WORKING see assembly 2
  } 
}

i only see slightly different register usage and slightly different
instructions like the final testjump jae vs je, bt, ...
i am definitelly no assembler guy, so maybe some assembler gurus
may interpret, and guess somehow what can go wrong with assembly 2,
while the bittest version seems to be clean. Thx in advance.

here it is again:

Assembly 1 (WORKING):

Code: Select all

	mov	QWORD PTR [rsp+24], rbx
	push	rdi
	sub	rsp, 32					; 00000020H
	test	BYTE PTR [rcx+392], 1
	mov	rdi, rdx
	mov	rbx, rcx
	je	$LN1@genCastleC
	movsxd	rax, DWORD PTR [rcx+404]
	mov	r8, QWORD PTR [rcx+8]
	mov	QWORD PTR [rsp+56], rsi
	or	r8, QWORD PTR [rcx]
	lea	r11, QWORD PTR [rax+rax*2]
	lea	rsi, OFFSET FLAT:lmsk
	mov	rax, QWORD PTR [rsi+r11*8]
	mov	r9, QWORD PTR [rsi+r11*8+8]
	mov	edx, 1
	and	rax, r8
	and	r9, r8
	or	rax, 1
	bsr	r10, rax
	mov	rax, QWORD PTR [rsi+r11*8+1536]
	and	rax, r8
	or	rax, 1
	bsr	rcx, rax
	mov	rax, QWORD PTR [rsi+r11*8+1544]
	and	rax, r8
	mov	r8, rax
	neg	r8
	and	r8, rax
	mov	rax, rdx
	shl	rax, cl
	add	r8, r8
	mov	ecx, r10d
	sub	r8, rax
	shl	rdx, cl
	mov	rax, r9
	and	r8, QWORD PTR [rsi+r11*8+1552]
	neg	rax
	and	rax, r9
	add	rax, rax
	sub	rax, rdx
	and	rax, QWORD PTR [rsi+r11*8+16]
	mov	rsi, QWORD PTR [rsp+56]
	or	r8, rax
	lea	rax, QWORD PTR rookAttacks$69207[rsp]
	mov	QWORD PTR rookAttacks$69207[rsp], r8
	bt	QWORD PTR [rax], 5
	jae	SHORT $LN1@genCastleC
	mov	rdx, rdi
	mov	rcx, rbx
	call	?generate_oow@@YAXPEAUpos_t@@PEAUmli_t@@@Z ; generate_oow
$LN1@genCastleC:
	mov	rbx, QWORD PTR [rsp+64]
	add	rsp, 32					; 00000020H
	pop	rdi
	ret	0
ASSEMBLY 2 (producing exceptions):

Code: Select all


	mov	QWORD PTR [rsp+16], rbx
	push	rdi
	sub	rsp, 32					; 00000020H
	test	BYTE PTR [rcx+392], 1
	mov	rdi, rdx
	mov	rbx, rcx
	je	$LN1@genCastleC
	movsxd	rax, DWORD PTR [rcx+404]
	mov	r8, QWORD PTR [rcx+8]
	mov	QWORD PTR [rsp+48], rsi
	or	r8, QWORD PTR [rcx]
	lea	r11, QWORD PTR [rax+rax*2]
	lea	rsi, OFFSET FLAT:lmsk
	mov	rax, QWORD PTR [rsi+r11*8]
	mov	r9, QWORD PTR [rsi+r11*8+8]
	mov	edx, 255				; 000000ffH
	and	rax, r8
	and	r9, r8
	or	rax, 1
	bsr	r10, rax
	mov	rax, QWORD PTR [rsi+r11*8+1536]
	and	rax, r8
	or	rax, 1
	bsr	rcx, rax
	mov	rax, QWORD PTR [rsi+r11*8+1544]
	and	rax, r8
	movzx	r8d, al
	neg	r8b
	and	r8b, al
	mov	eax, edx
	shl	al, cl
	add	r8b, r8b
	mov	ecx, r10d
	add	r8b, al
	shl	dl, cl
	movzx	eax, r9b
	and	r8b, BYTE PTR [rsi+r11*8+1552]
	neg	al
	and	al, r9b
	add	al, al
	add	al, dl
	and	al, BYTE PTR [rsi+r11*8+16]
	mov	rsi, QWORD PTR [rsp+48]
	or	r8b, al
	test	r8b, 32					; 00000020H
	je	SHORT $LN1@genCastleC
	mov	rdx, rdi
	mov	rcx, rbx
	call	?generate_oow@@YAXPEAUpos_t@@PEAUmli_t@@@Z ; generate_oow
$LN1@genCastleC:
	mov	rbx, QWORD PTR [rsp+56]
	add	rsp, 32					; 00000020H
	pop	rdi
	ret	0

thx, Michael
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

hmm, maybe it is not important what we can see in the second assembly,
maybe it s more important what we (at least i) can not see.

Where is the variable rookAttacks gone ?
adamh

Re: Very strange Bug

Post by adamh »

Hello Michael, while I am trying to help analyse the root of the problem you are ranting about my ignorance. Thanx :) It would be really nice to see the explicit declaration of ui64_t. Totally great!

The your posted code goes:

Code: Select all

extern __inline ui64_t attackR(sq_t s,ui64_t occ) 
I do not see any __int64 there. How can you say that it returns unsigned __int64 ??



My final paragraph is about how C++ matches arguments. "&" is a function call. When then are no explicit matches for the argument types C++ starts a complex series of attempts to fix it. The first mechanism is called promotion. The second is called type casting. If you allow this sort of implicit stuff to happen you lose control. And type casting may occur invisibly through reinterpret_cast or implicit default constructors. The mechanisms can in some cases become quite complex (but well defined). In Herb Sutters excellent "Exceptional C++" there are several chapters devoted to argument matching. (It may be that promotion will not occur here...)

I am willing to bet 10 beers, that what happens is a consequence of the C++ standard. And I am willing to bet one beer that it will not happen if you chuck out that ui64_t everywhere. Why not stick to unsigned __int64 if you intend to keep using the MS compiler.

:twisted:
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Very strange Bug

Post by Gerd Isenberg »

Gerd Isenberg wrote:The assembly looks a bit ugly, but correct.

Code: Select all

   mov   QWORD PTR [rsp+16], rbx   ; save rbx
   mov   edx, 255                    ; -1 byte wise
...
   mov   eax, edx                    ; -1 byte wise
   shl   al, cl                      ; al, lo file = -1 byte wise << bsr64(lo file | 1)
...
   shl   dl, cl                      ; dl, lo rank = -1 byte wise << bsr64(lo rank | 1)
I have to retract that the byte wise stuff is correct. It is not, the byte wise -1 shifts are wrong of course. The byte wise shift amount is implicit modulo 8 (edit 32).

May be you should use the cpw-macro if using 64-bit constants.
https://chessprogramming.wikispaces.com ... 0Bitboards

Code: Select all

#define C64(constantU64) constantU64##ULL

static __inline ui64_t attackLine(linemask_t *lmsk,ui64_t occ)
{
 ui64_t lo = -C64(1) << bsr64((lmsk->lineLo & occ)|1);
 ui64_t hi = lmsk->lineHi & occ;
 return(lmsk->lineEx & (2*(hi&-hi)+lo));
} 
Gerd
Last edited by Gerd Isenberg on Tue Feb 15, 2011 2:59 pm, edited 1 time in total.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

Hello Adam,

it was not my intetion to attack you in any from.
And i appreciate any help of course.

But if the first sentence of the current thread is

" attackR is returning (unsigned __int64) " ...

i felt teased a little bit. And it sound to me (maybe a language problem), like you put the whole thing
into some kind of ridiculousness, while i am sitting here already 2 days
to solve the problem. All you had to do was just reading a little bit
more carefully, especially like some of the other points you wrote about
like hgms "solution", or arguing to rewrite all attackfunctions...

now to be absolute clear and serious.

Code: Select all

typedef unsigned __int64 ui64_t;
is my typedefinition.

Michael
adamh

Re: Very strange Bug

Post by adamh »

Hmmm.... now that looks harmless indeed. And yes, perhaps I was reading a bit sloppily.

I am at work right now, and I have a big OTB chessgame tonight, so if I look deeper it will be during the midnight shift.

Looks like I will need to make a bit of effort to defend my beers now :oops:

Another question. Is this all (A) in a single compilation unit or is there (B) linkage involved? A, right? (I fell uncertain of how inlining works across separate compiles...)
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

Gerd Isenberg wrote:
Gerd Isenberg wrote:The assembly looks a bit ugly, but correct.

Code: Select all

   mov   QWORD PTR [rsp+16], rbx   ; save rbx
   mov   edx, 255                    ; -1 byte wise
...
   mov   eax, edx                    ; -1 byte wise
   shl   al, cl                      ; al, lo file = -1 byte wise << bsr64(lo file | 1)
...
   shl   dl, cl                      ; dl, lo rank = -1 byte wise << bsr64(lo rank | 1)
I have to retract that the byte wise stuff is correct. It is not, the byte wise -1 shifts are wrong of course. The byte wise shift amount is implicit modulo 8 (edit 32).

May be you should use the cpw-macro if using 64-bit constants.
https://chessprogramming.wikispaces.com ... 0Bitboards

Code: Select all

#define C64(constantU64) constantU64##ULL

static __inline ui64_t attackLine(linemask_t *lmsk,ui64_t occ)
{
 ui64_t lo = -C64(1) << bsr64((lmsk->lineLo & occ)|1);
 ui64_t hi = lmsk->lineHi & occ;
 return(lmsk->lineEx & (2*(hi&-hi)+lo));
} 
Gerd
Hello Gerd,

thx again. i will work on this, and report if it helps.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

adamh wrote:Hmmm.... now that looks harmless indeed. And yes, perhaps I was reading a bit sloppily.

I am at work right now, and I have a big OTB chessgame tonight, so if I look deeper it will be during the midnight shift.

Looks like I will need to make a bit of effort to defend my beers now :oops:

Another question. Is this all (A) in a single compilation unit or is there (B) linkage involved? A, right? (I fell uncertain of how inlining works across separate compiles...)
it is linkage involved, movegenerator and attackgetter are seperate moduls.

so (B), to be clear again :)

thx for your interest

Michael