Very strange Bug

Discussion of chess software programming and technical issues.

Moderator: Ras

Sven
Posts: 4052
Joined: Thu May 15, 2008 9:57 pm
Location: Berlin, Germany
Full name: Sven Schüle

Re: Very strange Bug

Post by Sven »

Desperado wrote:Sth. known about implicit type cast problems of 64bit values into boolean type
I would always write "if ((a&b) != 0) {...}" instead of "if (a&b) {...}" or "if ((a&b)) {...}". That helps to avoid some trouble and has practically no cost. Another advantage is readability.
Desperado wrote:if i should post my attackGetter Modul, i will do.
Yes, please ... at least the part including the code that does the "return" would be interesting.

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

Re: Very strange Bug

Post by Desperado »

Hello Sven, ok here it is...

Code: Select all

//******************************************************************************
//* AUTHOR: Michael Hoffmann
//* FILE  : attackG.cpp
//* ©     : Michael Hoffmann
//******************************************************************************

#include "nemo.h"

#pragma warning (disable: 4146)

static const int FILEDIR = 0;
static const int RANKDIR = 1;
static const int DIAGDIR = 2;
static const int ANTIDIR = 3;
static const int ALLDIRECTIONS = 4;

static const ui64_t lookupN[ID64] =
{
 0x20400           ,0x50800           ,0xA1100           ,0x142200          , 
 0x284400          ,0x508800          ,0xA01000          ,0x402000          , 
 0x2040004         ,0x5080008         ,0xA110011         ,0x14220022        , 
 0x28440044        ,0x50880088        ,0xA0100010        ,0x40200020        , 
 0x204000402       ,0x508000805       ,0xA1100110A       ,0x1422002214      , 
 0x2844004428      ,0x5088008850      ,0xA0100010A0      ,0x4020002040      , 
 0x20400040200     ,0x50800080500     ,0xA1100110A00     ,0x142200221400    , 
 0x284400442800    ,0x508800885000    ,0xA0100010A000    ,0x402000204000    , 
 0x2040004020000   ,0x5080008050000   ,0xA1100110A0000   ,0x14220022140000  , 
 0x28440044280000  ,0x50880088500000  ,0xA0100010A00000  ,0x40200020400000  , 
 0x204000402000000 ,0x508000805000000 ,0xA1100110A000000 ,0x1422002214000000, 
 0x2844004428000000,0x5088008850000000,0xA0100010A0000000,0x4020002040000000, 
 0x400040200000000 ,0x800080500000000 ,0x1100110A00000000,0x2200221400000000, 
 0x4400442800000000,0x8800885000000000,0x100010A000000000,0x2000204000000000, 
 0x4020000000000   ,0x8050000000000   ,0x110A0000000000  ,0x22140000000000  , 
 0x44280000000000  ,0x88500000000000  ,0x10A00000000000  ,0x20400000000000  , 
};

static const ui64_t lookupK[ID64] =
{
 0x302             ,0x705             ,0xE0A             ,0x1C14            , 
 0x3828            ,0x7050            ,0xE0A0            ,0xC040            , 
 0x30203           ,0x70507           ,0xE0A0E           ,0x1C141C          , 
 0x382838          ,0x705070          ,0xE0A0E0          ,0xC040C0          , 
 0x3020300         ,0x7050700         ,0xE0A0E00         ,0x1C141C00        , 
 0x38283800        ,0x70507000        ,0xE0A0E000        ,0xC040C000        , 
 0x302030000       ,0x705070000       ,0xE0A0E0000       ,0x1C141C0000      , 
 0x3828380000      ,0x7050700000      ,0xE0A0E00000      ,0xC040C00000      , 
 0x30203000000     ,0x70507000000     ,0xE0A0E000000     ,0x1C141C000000    , 
 0x382838000000    ,0x705070000000    ,0xE0A0E0000000    ,0xC040C0000000    , 
 0x3020300000000   ,0x7050700000000   ,0xE0A0E00000000   ,0x1C141C00000000  , 
 0x38283800000000  ,0x70507000000000  ,0xE0A0E000000000  ,0xC040C000000000  , 
 0x302030000000000 ,0x705070000000000 ,0xE0A0E0000000000 ,0x1C141C0000000000, 
 0x3828380000000000,0x7050700000000000,0xE0A0E00000000000,0xC040C00000000000, 
 0x203000000000000 ,0x507000000000000 ,0xA0E000000000000 ,0x141C000000000000, 
 0x2838000000000000,0x5070000000000000,0xA0E0000000000000,0x40C0000000000000,
};

static const ui64_t lookupP[ID2][ID64] =
{
 //whitePawnAttacks
{
 0x200             ,0x500             ,0xA00             ,0x1400            , 
 0x2800            ,0x5000            ,0xA000            ,0x4000            , 
 0x20000           ,0x50000           ,0xA0000           ,0x140000          , 
 0x280000          ,0x500000          ,0xA00000          ,0x400000          , 
 0x2000000         ,0x5000000         ,0xA000000         ,0x14000000        , 
 0x28000000        ,0x50000000        ,0xA0000000        ,0x40000000        , 
 0x200000000       ,0x500000000       ,0xA00000000       ,0x1400000000      , 
 0x2800000000      ,0x5000000000      ,0xA000000000      ,0x4000000000      , 
 0x20000000000     ,0x50000000000     ,0xA0000000000     ,0x140000000000    , 
 0x280000000000    ,0x500000000000    ,0xA00000000000    ,0x400000000000    , 
 0x2000000000000   ,0x5000000000000   ,0xA000000000000   ,0x14000000000000  , 
 0x28000000000000  ,0x50000000000000  ,0xA0000000000000  ,0x40000000000000  , 
 0x200000000000000 ,0x500000000000000 ,0xA00000000000000 ,0x1400000000000000, 
 0x2800000000000000,0x5000000000000000,0xA000000000000000,0x4000000000000000, 
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x0               ,0x0               ,0x0               ,0x0
},
//blackPawnAttacks
{
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x2               ,0x5               ,0xA               ,0x14              , 
 0x28              ,0x50              ,0xA0              ,0x40              , 
 0x200             ,0x500             ,0xA00             ,0x1400            , 
 0x2800            ,0x5000            ,0xA000            ,0x4000            , 
 0x20000           ,0x50000           ,0xA0000           ,0x140000          , 
 0x280000          ,0x500000          ,0xA00000          ,0x400000          , 
 0x2000000         ,0x5000000         ,0xA000000         ,0x14000000        , 
 0x28000000        ,0x50000000        ,0xA0000000        ,0x40000000        , 
 0x200000000       ,0x500000000       ,0xA00000000       ,0x1400000000      , 
 0x2800000000      ,0x5000000000      ,0xA000000000      ,0x4000000000      , 
 0x20000000000     ,0x50000000000     ,0xA0000000000     ,0x140000000000    , 
 0x280000000000    ,0x500000000000    ,0xA00000000000    ,0x400000000000    , 
 0x2000000000000   ,0x5000000000000   ,0xA000000000000   ,0x14000000000000  , 
 0x28000000000000  ,0x50000000000000  ,0xA0000000000000  ,0x40000000000000 
}
};

struct linemask_t {ui64_t lineLo,lineHi,lineEx;};
static linemask_t lmsk[ALLDIRECTIONS][ID64];

//******************************************************************************
//* init linemasks
//******************************************************************************

void initAttackGetter(void)
{
 for(int i=a1;i<=h8;i++)
 {
  lmsk[FILEDIR][i].lineEx = (fileMask(i) ^ bit(i));
  lmsk[FILEDIR][i].lineLo = (fileMask(i) ^ bit(i)) & loBits(i);
  lmsk[FILEDIR][i].lineHi = (fileMask(i) ^ bit(i)) & hiBits(i);

  lmsk[RANKDIR][i].lineEx = (rankMask(i) ^ bit(i));
  lmsk[RANKDIR][i].lineLo = (rankMask(i) ^ bit(i)) & loBits(i);
  lmsk[RANKDIR][i].lineHi = (rankMask(i) ^ bit(i)) & hiBits(i);

  lmsk[DIAGDIR][i].lineEx = (diagMask(i) ^ bit(i));
  lmsk[DIAGDIR][i].lineLo = (diagMask(i) ^ bit(i)) & loBits(i);
  lmsk[DIAGDIR][i].lineHi = (diagMask(i) ^ bit(i)) & hiBits(i);

  lmsk[ANTIDIR][i].lineEx = (antiMask(i) ^ bit(i));
  lmsk[ANTIDIR][i].lineLo = (antiMask(i) ^ bit(i)) & loBits(i);
  lmsk[ANTIDIR][i].lineHi = (antiMask(i) ^ bit(i)) & hiBits(i);
 }
}

//******************************************************************************
//* obstruction difference
//******************************************************************************

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

//******************************************************************************
//* attackGetter
//******************************************************************************

extern ui64_t (*attack[ID16]) (sq_t,ui64_t) =
{
 NULL,NULL,
 attackWP,attackBP,attackN ,attackN ,attackB ,attackB ,attackB ,
 attackB ,attackR ,attackR ,attackQ ,attackQ ,attackK ,attackK
};

extern __inline ui64_t attackWP(sq_t s,ui64_t dmy){return(lookupP[white][s]);}
extern __inline ui64_t attackBP(sq_t s,ui64_t dmy){return(lookupP[black][s]);}
extern __inline ui64_t attackN(sq_t s,ui64_t dmy) {return(lookupN[s]);}
extern __inline ui64_t attackK(sq_t s,ui64_t dmy) {return(lookupK[s]);}

extern __inline ui64_t attackB(sq_t s,ui64_t occ)
{return(attackLine(&lmsk[DIAGDIR][s],occ) | attackLine(&lmsk[ANTIDIR][s],occ));}

extern __inline ui64_t attackR(sq_t s,ui64_t occ)
{return(attackLine(&lmsk[FILEDIR][s],occ) | attackLine(&lmsk[RANKDIR][s],occ));}

extern __inline ui64_t attackQ(sq_t s,ui64_t occ)
{return(attackB(s,occ)|attackR(s,occ));}

and some more snippets... (from bittwiddle.cpp)

Code: Select all


extern __inline ui64_t bit(int id) {return((ui64_t)1<<id);}
extern __inline ui64_t hiBits(int id) {return(0xFFFFFFFFFFFFFFFF << id);}
extern __inline ui64_t loBits(int id) {return(bit(id)-1);}

well, you proposal to compare the expression against a conrete number
also doesnt help. Readability is little bit a matter of taste imho.

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

Re: Very strange Bug

Post by Gerd Isenberg »

Desperado wrote:

Code: Select all


if((attackR(KING(black),OCCUPIED) & bF1)) {codeblock}

Hi Michael,
can you post the generated assembly of the above source line, which behaves wrong? The obstruction diff rook attack getter and the test instruction.

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

Re: Very strange Bug

Post by Desperado »

Hello Gerd,

Code: Select all


extern __inline ui64_t attackR(sq_t s,ui64_t occ)
{return(attackLine(&lmsk[FILEDIR][s],occ) | attackLine(&lmsk[RANKDIR][s],occ));}

Code: Select all


	mov	QWORD PTR [rsp+8], rbx
	lea	rbx, OFFSET FLAT:lmsk
	movsxd	rax, ecx
	or	r8, -1
	lea	r11, QWORD PTR [rax+rax*2]
	mov	rax, QWORD PTR [rbx+r11*8]
	mov	r9, QWORD PTR [rbx+r11*8+8]
	and	rax, rdx
	and	r9, rdx
	or	rax, 1
	bsr	r10, rax
	mov	rax, QWORD PTR [rbx+r11*8+1536]
	and	rax, rdx
	or	rax, 1
	bsr	rcx, rax
	mov	rax, QWORD PTR [rbx+r11*8+1544]
	and	rax, rdx
	mov	rdx, rax
	neg	rdx
	and	rdx, rax
	mov	rax, r8
	shl	rax, cl
	mov	ecx, r10d
	lea	rax, QWORD PTR [rax+rdx*2]
	shl	r8, cl
	mov	rdx, r9
	and	rax, QWORD PTR [rbx+r11*8+1552]
	neg	rdx
	and	rdx, r9
	lea	rcx, QWORD PTR [r8+rdx*2]
	and	rcx, QWORD PTR [rbx+r11*8+16]
	mov	rbx, QWORD PTR [rsp+8]
	or	rax, rcx
	ret	0

Code: Select all


static void genCastleCheck(pos_t *pos,mli_t *mli)
{
 if((pos->cst & oow)  && (attackR(KING(black),OCCUPIED) & bF1)) {generate_oow(pos,mli);}
}

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

just put the statement into an extra function, so the assembly is easier to read. The error occurs anyway.

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

Re: Very strange Bug

Post by Desperado »

... and the the current debug/test routine which is in work.

Code: Select all


void testChecks(pos_t *pos)
{
 mli_t mli[1];
 mli_t chk[1];
 undo_t undo[1];
 mv_t mve;
 int  check;

 pos->incheck = squareIsAttacked(pos,KING(pos->ctm),pos->ctm^side);
 pos->pinned  = pinned(pos,pos->ctm);

 movelistClr(chk);
 movelistClr(mli);
 generateChecks[pos->ctm](pos,chk);
 //generateQuiet[pos->ctm](pos,mli);

 //test1: move really checks
 while(mve = movelistGet(chk))
 {
  if(!moveIsLegal(pos,mve))continue;

  moveDo(pos,undo,mve);
  check = squareIsAttacked(pos,KING(pos->ctm),pos->ctm^side);
  moveUndo(pos,undo,mve);

  if(!check)
  {
   generateChecks[pos->ctm](pos,mli);
   printf("\nLIST: ");
   for(int i=0;i<mli->size;i++)printMove(mve);
   printPosition(pos);
  }
 }

 /*TODO*/
}

ok, i hope one of you can find sth. thx
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Very strange Bug

Post by bob »

Desperado wrote:Hello Sven, ok here it is...

Code: Select all

//******************************************************************************
//* AUTHOR: Michael Hoffmann
//* FILE  : attackG.cpp
//* ©     : Michael Hoffmann
//******************************************************************************

#include "nemo.h"

#pragma warning (disable: 4146)

static const int FILEDIR = 0;
static const int RANKDIR = 1;
static const int DIAGDIR = 2;
static const int ANTIDIR = 3;
static const int ALLDIRECTIONS = 4;

static const ui64_t lookupN[ID64] =
{
 0x20400           ,0x50800           ,0xA1100           ,0x142200          , 
 0x284400          ,0x508800          ,0xA01000          ,0x402000          , 
 0x2040004         ,0x5080008         ,0xA110011         ,0x14220022        , 
 0x28440044        ,0x50880088        ,0xA0100010        ,0x40200020        , 
 0x204000402       ,0x508000805       ,0xA1100110A       ,0x1422002214      , 
 0x2844004428      ,0x5088008850      ,0xA0100010A0      ,0x4020002040      , 
 0x20400040200     ,0x50800080500     ,0xA1100110A00     ,0x142200221400    , 
 0x284400442800    ,0x508800885000    ,0xA0100010A000    ,0x402000204000    , 
 0x2040004020000   ,0x5080008050000   ,0xA1100110A0000   ,0x14220022140000  , 
 0x28440044280000  ,0x50880088500000  ,0xA0100010A00000  ,0x40200020400000  , 
 0x204000402000000 ,0x508000805000000 ,0xA1100110A000000 ,0x1422002214000000, 
 0x2844004428000000,0x5088008850000000,0xA0100010A0000000,0x4020002040000000, 
 0x400040200000000 ,0x800080500000000 ,0x1100110A00000000,0x2200221400000000, 
 0x4400442800000000,0x8800885000000000,0x100010A000000000,0x2000204000000000, 
 0x4020000000000   ,0x8050000000000   ,0x110A0000000000  ,0x22140000000000  , 
 0x44280000000000  ,0x88500000000000  ,0x10A00000000000  ,0x20400000000000  , 
};

static const ui64_t lookupK[ID64] =
{
 0x302             ,0x705             ,0xE0A             ,0x1C14            , 
 0x3828            ,0x7050            ,0xE0A0            ,0xC040            , 
 0x30203           ,0x70507           ,0xE0A0E           ,0x1C141C          , 
 0x382838          ,0x705070          ,0xE0A0E0          ,0xC040C0          , 
 0x3020300         ,0x7050700         ,0xE0A0E00         ,0x1C141C00        , 
 0x38283800        ,0x70507000        ,0xE0A0E000        ,0xC040C000        , 
 0x302030000       ,0x705070000       ,0xE0A0E0000       ,0x1C141C0000      , 
 0x3828380000      ,0x7050700000      ,0xE0A0E00000      ,0xC040C00000      , 
 0x30203000000     ,0x70507000000     ,0xE0A0E000000     ,0x1C141C000000    , 
 0x382838000000    ,0x705070000000    ,0xE0A0E0000000    ,0xC040C0000000    , 
 0x3020300000000   ,0x7050700000000   ,0xE0A0E00000000   ,0x1C141C00000000  , 
 0x38283800000000  ,0x70507000000000  ,0xE0A0E000000000  ,0xC040C000000000  , 
 0x302030000000000 ,0x705070000000000 ,0xE0A0E0000000000 ,0x1C141C0000000000, 
 0x3828380000000000,0x7050700000000000,0xE0A0E00000000000,0xC040C00000000000, 
 0x203000000000000 ,0x507000000000000 ,0xA0E000000000000 ,0x141C000000000000, 
 0x2838000000000000,0x5070000000000000,0xA0E0000000000000,0x40C0000000000000,
};

static const ui64_t lookupP[ID2][ID64] =
{
 //whitePawnAttacks
{
 0x200             ,0x500             ,0xA00             ,0x1400            , 
 0x2800            ,0x5000            ,0xA000            ,0x4000            , 
 0x20000           ,0x50000           ,0xA0000           ,0x140000          , 
 0x280000          ,0x500000          ,0xA00000          ,0x400000          , 
 0x2000000         ,0x5000000         ,0xA000000         ,0x14000000        , 
 0x28000000        ,0x50000000        ,0xA0000000        ,0x40000000        , 
 0x200000000       ,0x500000000       ,0xA00000000       ,0x1400000000      , 
 0x2800000000      ,0x5000000000      ,0xA000000000      ,0x4000000000      , 
 0x20000000000     ,0x50000000000     ,0xA0000000000     ,0x140000000000    , 
 0x280000000000    ,0x500000000000    ,0xA00000000000    ,0x400000000000    , 
 0x2000000000000   ,0x5000000000000   ,0xA000000000000   ,0x14000000000000  , 
 0x28000000000000  ,0x50000000000000  ,0xA0000000000000  ,0x40000000000000  , 
 0x200000000000000 ,0x500000000000000 ,0xA00000000000000 ,0x1400000000000000, 
 0x2800000000000000,0x5000000000000000,0xA000000000000000,0x4000000000000000, 
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x0               ,0x0               ,0x0               ,0x0
},
//blackPawnAttacks
{
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x0               ,0x0               ,0x0               ,0x0               , 
 0x2               ,0x5               ,0xA               ,0x14              , 
 0x28              ,0x50              ,0xA0              ,0x40              , 
 0x200             ,0x500             ,0xA00             ,0x1400            , 
 0x2800            ,0x5000            ,0xA000            ,0x4000            , 
 0x20000           ,0x50000           ,0xA0000           ,0x140000          , 
 0x280000          ,0x500000          ,0xA00000          ,0x400000          , 
 0x2000000         ,0x5000000         ,0xA000000         ,0x14000000        , 
 0x28000000        ,0x50000000        ,0xA0000000        ,0x40000000        , 
 0x200000000       ,0x500000000       ,0xA00000000       ,0x1400000000      , 
 0x2800000000      ,0x5000000000      ,0xA000000000      ,0x4000000000      , 
 0x20000000000     ,0x50000000000     ,0xA0000000000     ,0x140000000000    , 
 0x280000000000    ,0x500000000000    ,0xA00000000000    ,0x400000000000    , 
 0x2000000000000   ,0x5000000000000   ,0xA000000000000   ,0x14000000000000  , 
 0x28000000000000  ,0x50000000000000  ,0xA0000000000000  ,0x40000000000000 
}
};

struct linemask_t {ui64_t lineLo,lineHi,lineEx;};
static linemask_t lmsk[ALLDIRECTIONS][ID64];

//******************************************************************************
//* init linemasks
//******************************************************************************

void initAttackGetter(void)
{
 for(int i=a1;i<=h8;i++)
 {
  lmsk[FILEDIR][i].lineEx = (fileMask(i) ^ bit(i));
  lmsk[FILEDIR][i].lineLo = (fileMask(i) ^ bit(i)) & loBits(i);
  lmsk[FILEDIR][i].lineHi = (fileMask(i) ^ bit(i)) & hiBits(i);

  lmsk[RANKDIR][i].lineEx = (rankMask(i) ^ bit(i));
  lmsk[RANKDIR][i].lineLo = (rankMask(i) ^ bit(i)) & loBits(i);
  lmsk[RANKDIR][i].lineHi = (rankMask(i) ^ bit(i)) & hiBits(i);

  lmsk[DIAGDIR][i].lineEx = (diagMask(i) ^ bit(i));
  lmsk[DIAGDIR][i].lineLo = (diagMask(i) ^ bit(i)) & loBits(i);
  lmsk[DIAGDIR][i].lineHi = (diagMask(i) ^ bit(i)) & hiBits(i);

  lmsk[ANTIDIR][i].lineEx = (antiMask(i) ^ bit(i));
  lmsk[ANTIDIR][i].lineLo = (antiMask(i) ^ bit(i)) & loBits(i);
  lmsk[ANTIDIR][i].lineHi = (antiMask(i) ^ bit(i)) & hiBits(i);
 }
}

//******************************************************************************
//* obstruction difference
//******************************************************************************

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

//******************************************************************************
//* attackGetter
//******************************************************************************

extern ui64_t (*attack[ID16]) (sq_t,ui64_t) =
{
 NULL,NULL,
 attackWP,attackBP,attackN ,attackN ,attackB ,attackB ,attackB ,
 attackB ,attackR ,attackR ,attackQ ,attackQ ,attackK ,attackK
};

extern __inline ui64_t attackWP(sq_t s,ui64_t dmy){return(lookupP[white][s]);}
extern __inline ui64_t attackBP(sq_t s,ui64_t dmy){return(lookupP[black][s]);}
extern __inline ui64_t attackN(sq_t s,ui64_t dmy) {return(lookupN[s]);}
extern __inline ui64_t attackK(sq_t s,ui64_t dmy) {return(lookupK[s]);}

extern __inline ui64_t attackB(sq_t s,ui64_t occ)
{return(attackLine(&lmsk[DIAGDIR][s],occ) | attackLine(&lmsk[ANTIDIR][s],occ));}

extern __inline ui64_t attackR(sq_t s,ui64_t occ)
{return(attackLine(&lmsk[FILEDIR][s],occ) | attackLine(&lmsk[RANKDIR][s],occ));}

extern __inline ui64_t attackQ(sq_t s,ui64_t occ)
{return(attackB(s,occ)|attackR(s,occ));}

and some more snippets... (from bittwiddle.cpp)

Code: Select all


extern __inline ui64_t bit(int id) {return((ui64_t)1<<id);}
extern __inline ui64_t hiBits(int id) {return(0xFFFFFFFFFFFFFFFF << id);}
extern __inline ui64_t loBits(int id) {return(bit(id)-1);}

well, you proposal to compare the expression against a conrete number
also doesnt help. Readability is little bit a matter of taste imho.

cheers, Michael
As a long-time C programmer, I prefer if (A&B) as opposed to if (A&B != 0) myself. I know what the A & B means. now of course, if you really mean A && B then one might get into more trouble... :)

I think the .asm file will be the most useful as mixing 32 and 64 bit stuff is always an invitation for bugs to slip in....
Gerd Isenberg
Posts: 2251
Joined: Wed Mar 08, 2006 8:47 pm
Location: Hattingen, Germany

Re: Very strange Bug

Post by Gerd Isenberg »

The assembly looks a bit ugly, but correct. Since only the attack on square f1 (bitmask 1<<5 == 0x20 == 32) is finally needed, all the bit calculations of the file- and rank attacks, the union and final test instruction with 32 appears on the first rank byte wise, which often does not give optimal code with this compiler. The question is whether the reported assembly code is the one executed, when it is embedded/inlined by surrounding code, which may somehow introduce an obscure bug by the compiler, may be due to the bytewise stuff.

Code: Select all

   mov   QWORD PTR [rsp+16], rbx   ; save rbx
   push   rdi                      ; save rdi
   sub   rsp, 32                   ; Stack alignment              
   test   BYTE PTR [rcx+392], 1  ; pos->cst & oow, set zero flag
   mov   rdi, rdx                ; mli
   mov   rbx, rcx                ; pos
   je   $LN1@genCastleC          ; if (( pos->cst & oow) == 0 ) return;
   movsxd   rax, DWORD PTR [rcx+404] ; signed int square extended to qword 
   mov   r8, QWORD PTR [rcx+8]   ; black pieces ?  
   mov   QWORD PTR [rsp+48], rsi ; save rsi
   or   r8, QWORD PTR [rcx]      ; or white pieces -> occupancy in r8
   lea   r11, QWORD PTR [rax+rax*2]  ; r11 = 3*sq index scaling for lmsk struct
   lea   rsi, OFFSET FLAT:lmsk       ; rsi = lmsk
   mov   rax, QWORD PTR [rsi+r11*8]  ; rax = low rank[sq]
   mov   r9, QWORD PTR [rsi+r11*8+8] ; r9  = high rank[sq]
   mov   edx, 255                    ; -1 byte wise
   and   rax, r8                     ; rax = low rank & occ
   and   r9, r8                      ; r9  = high rank & occ
   or   rax, 1                       ; lo rank |= 1
   bsr   r10, rax                    ; r10 = bsr64(lo rank | 1)
   mov   rax, QWORD PTR [rsi+r11*8+1536] ; rax = low file[sq]
   and   rax, r8                     ; rax = low file & occ
   or   rax, 1                       ; low file |= 1
   bsr   rcx, rax                    ; rcx = bsr64(lo file | 1)
   mov   rax, QWORD PTR [rsi+r11*8+1544] ; rax = high file[sq]
   and   rax, r8                     ; rax = high rank & occ
   movzx   r8d, al                   ; hi rank, byte wise, zero extented
   neg   r8b                         ; -hi rank, byte wise
   and   r8b, al                     ; r8b = hi & -hi rank byte wise
   mov   eax, edx                    ; -1 byte wise
   shl   al, cl                      ; al, lo file = -1 byte wise << bsr64(lo file | 1)
   add   r8b, r8b                    ; 2*hi, rank, byte wise
   mov   ecx, r10d                   ; lo rank = bsr64(lo rank | 1)
   add   r8b, al                     ; 2*hi + lo, rank, byte wise
   shl   dl, cl                      ; dl, lo rank = -1 byte wise << bsr64(lo rank | 1)
   movzx   eax, r9b                  ; eax = high rank & occ, byte wise, zero extended
   and   r8b, BYTE PTR [rsi+r11*8+1552] ; lmsk->rankEx & (2*(hi&-hi)+lo)
   neg   al                          ; -hi file, byte wise
   and   al, r9b                     ; al, hi file = hi & -hi file, byte wise
   add   al, al                      ; 2*hi file, byte wise
   add   al, dl                      ; 2*hi + lo, file, byte wise
   and   al, BYTE PTR [rsi+r11*8+16] ; lmsk->fileEx & (2*(hi&-hi)+lo)
   mov   rsi, QWORD PTR [rsp+48] ; restore rsi
   or   r8b, al                      ; rook attacks, byte wise (1.rank only)
   test   r8b, 32                    ; f1 attacked
   je   SHORT $LN1@genCastleC        ; no, if zero skip generate_oow
   mov   rdx, rdi                    ; pass mli
   mov   rcx, rbx                    ; pass pos
   call   ?generate_oow@@YAXPEAUpos_t@@PEAUmli_t@@@Z ; generate_oow
$LN1@genCastleC:
   mov   rbx, QWORD PTR [rsp+56] ; restore rbx
   add   rsp, 32                 ; restore stack
   pop   rdi                     ; restore rdi 
   ret   0
see also 5 Stack alignment in
http://www.agner.org/optimize/calling_conventions.pdf

I would pack the square indexed file and rank masks together, maybe with some other stuff padded to 8 bitboards, aligned to one 64 byte cacheline. The code also demonstrates the extra movsxd dword to qword sign-extension due to the signed square integer.

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

Code: Select all

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);
    }
  }
}
Gerd
adamh

Re: Very strange Bug

Post by adamh »

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 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 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.

(Funny stuff could possibly occur in the possible argument promotion - and matching - in the call to the binary "&" operator)
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Very strange Bug

Post by bob »

Desperado wrote:
hgm wrote:That is not really conclusive, as the 'random left-over' could be put there by attackR, which would make it always the same no matter where you move this code. Furthermore, a random left-over is unlikely to be zero, even if it woud be different all the time.

If you want to get to the bottom of this, you could try to simplify the attackR routine to one that only does 'return 0;', and your main program to one that only does the two code-lines you posted, and then see if the error still occurs. If it does, you could compile to assembler, and post the assembly code generated for attackR(), and for main(), so we can see what is done wrong, and if the compiler is to blame for this.
Thx so far, all i can say for now is that i have introduced a

extern __inline ui64_t attackRTest(sq_t,ui64_t); function.

I tried : - return(constant 0)
- return(EXP == 0), so the compiler may not optimize sth. here.

i have added the function, so i can run my perft collection with about 12 billion nodes, which by the way doesnt produce any error. That indicates
that my attack routines are working.

But unfortunatelly returning 0 does not lead to any kind of exception.
Even if this line of code takes 2 weeks to solve, i will get the answer :shock: :?
Maybe the register usage is now different or whatever...

I fear there are more bugs of this kind, i only catched it here
because i rewrite my movgen which i am intensively testing therefore.
The equivalent code for black, does not produce any exceptions for example.

What do you think of, if i work around with sth like

#define BOOL64(EXP) ((int)(EXP))

Basically i dont like such workarounds, but it would do the job
and i would be on the safe side ?!

Michael
This is all bad. Pick a data type and use it consistently. Don't mix and mingle 64 bit and 32 bit stuff and expect anything but trouble, particularly each time you move to a new system, or a new compiler...

There's no advantage to using 32 bit stuff unless you have large arrays and are trying to reduce your cache footprint. But if you use 32 bit stuff, avoid mixing it with 64 bit stuff. The sign extension stuff is just one reason to do that and avoid having extra instructions scattered through your code.
User avatar
Desperado
Posts: 879
Joined: Mon Dec 15, 2008 11:45 am

Re: Very strange Bug

Post by Desperado »

Hello Bob,

well my data is 99,9% standard "int", with the exceptions for
bitboards and hash numbers which are ui64_t (ms: unsigned __int64).

if you think of that, ok. But if you think also to replace the standard
integers with 64 bit integers i would have to think about it first.

of course i dont like too an explicit cast or using temporary values
where it is not necessary by default.

strange thing this one...

cheers