summaryrefslogtreecommitdiff
path: root/src/x64.asm
diff options
context:
space:
mode:
authorScott Gasch <[email protected]>2026-08-23 11:28:49 -0700
committerScott Gasch <[email protected]>2026-08-23 11:28:49 -0700
commitdf8facc22815f9eca0897e27ccce30701ba95322 (patch)
treebf90ad7ff19383fbac9b0a163f31bf3a9fb11fbe /src/x64.asm
parentdc0c9dbf405095a6483705b153f4c85c64499d4e (diff)
Clean X64 build and ported GetAttacks to x64.
Diffstat (limited to 'src/x64.asm')
-rw-r--r--src/x64.asm247
1 files changed, 192 insertions, 55 deletions
diff --git a/src/x64.asm b/src/x64.asm
index e80dc67..89351f2 100644
--- a/src/x64.asm
+++ b/src/x64.asm
@@ -3,8 +3,8 @@
[SEGMENT .data]
-[EXTERN _g_VectorDelta]
-[EXTERN _g_PieceData]
+[EXTERN g_VectorDelta]
+[EXTERN g_PieceData]
%ifdef OSX
;;; Note: The reason for this OSX stuff is that there is a bug in the mac
@@ -24,8 +24,8 @@ _g_NasmPieceData:
alignb 32, db 0
times 4 * 4 * 8 db 0
%else
-[EXTERN _g_VectorDelta]
-[EXTERN _g_PieceData]
+[EXTERN g_VectorDelta]
+[EXTERN g_PieceData]
%endif
[SEGMENT .text]
@@ -39,8 +39,7 @@ _g_NasmPieceData:
;;
LastBit:
_LastBit:
- int 3
- bsr rax, rcx
+ bsr rax, rdi
jnz .found
xor rax, rax
ret
@@ -50,14 +49,13 @@ _LastBit:
[GLOBAL FirstBit]
[GLOBAL _FirstBit]
- ;;
+ ;;
;; ULONGLONG CDECL
;; FirstBit(BITBOARD bb)
- ;;
+ ;;
FirstBit:
_FirstBit:
- ;movq rcx, [rsp+8]
- bsf rax, rcx
+ bsf rax, rdi
jnz .found
xor rax, rax
ret
@@ -67,14 +65,14 @@ _FirstBit:
[GLOBAL CountBits]
[GLOBAL _CountBits]
- ;;
+ ;;
;; ULONGLONG CDECL
;; CountBits(BITBOARD bb)
- ;;
-CountBits:
+ ;;
+CountBits:
_CountBits:
xor rax, rax
- mov rcx, [esp+8]
+ mov rcx, rdi
test rcx, rcx
jz .done
.again: add rax, 1
@@ -94,52 +92,191 @@ _CountBits:
iDelta dd -17
dd +15
-%define uSide ebp+0x14
-%define cSquare ebp+0x10
-%define pos ebp+0xC
-%define pList ebp+8
-;; retaddr ebp+4
-;; old ebp ebp
-;; old ebx ebp-4
-;; old esi ebp-8
-;; old edi ebp-0xC
-%define pOldList ebp-0x10
-%define c ebp-0x14
-%define x ebp-0x18
+;; [rbp-0x8] is the saved rbx from the "push rbx" in the prologue below;
+;; locals must start below that, not alias it.
+%define pOldList qword [rbp-0x10]
+%define c dword [rbp-0x14]
+%define x dword [rbp-0x18]
+%define cSquareSave dword [rbp-0x1C]
+%define uSideSave dword [rbp-0x20]
%define _cNonPawns 0x478
%define _uNonPawnCount 0x500
%define _rgSquare 0x0
-
- ;;
- ;; void CDECL
- ;; GetAttacks(SEE_LIST *pList, ; ebp + 8
- ;; POSITION *pos, ; ebp + 0xC
- ;; COOR cSquare, ; ebp + 0x10
- ;; ULONG uSide) ; ebp + 0x14
- ;;
+
+ ;;
+ ;; void CDECL (SysV AMD64 ABI)
+ ;; GetAttacks(SEE_LIST *pList, ; rdi
+ ;; POSITION *pos, ; rsi
+ ;; COOR cSquare, ; edx
+ ;; ULONG uSide) ; ecx
+ ;;
+ ;; NOTE: a square (COOR) is always >= 0, but a square-minus-
+ ;; square delta is not. Any such delta must be sign-extended
+ ;; into a 64-bit register (movsxd) before being used as a
+ ;; scaled memory index: using the raw 32-bit register zero-
+ ;; extends it into a huge positive 64-bit value instead of the
+ ;; intended negative offset. This is the same bug that turned
+ ;; up in the C DISTANCE macro -- see chess.h.
+ ;;
GetAttacks:
_GetAttacks:
- int 3
+ push rbp
+ mov rbp, rsp
+ push rbx
+ sub rsp, 0x20
+
+ mov cSquareSave, edx
+ mov uSideSave, ecx
+
+ mov pOldList, rdi ; pOldList = pList
+ mov dword [rdi], 0 ; pList->uCount = 0
+ add rdi, 4 ; rdi = &pList->data[0]
+
+ ;; ebx = c = cSquare + iDelta[uSide]
+ movsxd rax, uSideSave
+ mov ebx, [iDelta+rax*4]
+ add ebx, cSquareSave
+
+ ;; ecx = pPawn = BLACK_PAWN | uColor
+ mov ecx, uSideSave
+ or ecx, 2
+
+ ;;
+ ;; Check the pawns
+ ;;
+ test ebx, 0x88
+ jnz .try_other_pawn
+ movsxd rax, ebx
+ mov eax, dword [rsi+rax*8+_rgSquare]
+ cmp eax, ecx
+ jne .try_other_pawn
+ mov rax, pOldList
+ mov dword [rax], 1
+ mov dword [rdi], ecx
+ mov dword [rdi+4], ebx
+ mov dword [rdi+8], 100
+ add rdi, 12
+
+.try_other_pawn:
+ add ebx, 2
+ test ebx, 0x88
+ jnz .done_pawns
+ movsxd rax, ebx
+ mov eax, dword [rsi+rax*8+_rgSquare]
+ cmp eax, ecx
+ jne .done_pawns
+ mov dword [rdi], ecx
+ mov dword [rdi+4], ebx
+ mov dword [rdi+8], 100
+ mov rax, pOldList
+ add rdi, 12
+ add dword [rax], 1
+
+.done_pawns:
+ ;;
+ ;; Do pieces
+ ;;
+ ;; x = pos->uNonPawnCount[uSide][0]
+ mov eax, uSideSave
+ shl eax, 5 ; uSide * 32
+ movsxd rax, eax
+ mov ecx, dword [rsi+rax+_uNonPawnCount]
+ mov x, ecx
+
+.loop_continue:
+ mov ecx, x
+ sub ecx, 1
+ cmp ecx, 0
+ jl near .done
+ mov x, ecx
+
+ ;; eax = c = pos->cNonPawns[uSide][x]
+ mov eax, uSideSave
+ shl eax, 4
+ add eax, ecx ; eax = uSide*16 + x
+ movsxd rax, eax
+ mov eax, dword [rsi+rax*4+_cNonPawns]
+ mov c, eax
+
+ ;; ecx = p = pos->pSquare[c]
+ movsxd rax, eax
+ mov ecx, dword [rsi+rax*8+_rgSquare]
+
+ ;; r8 = iIndex = c - cSquare (must stay signed)
+ sub eax, cSquareSave
+ movsxd r8, eax
+
+ ;;
+ ;; If there is no way for that kind of piece to get to this
+ ;; square then keep looking.
+ ;;
+ mov ebx, 1
+ mov r9d, ecx ; r9 = p, survives to .nothing_blocks
+ shr ecx, 1
+ shl ebx, cl
+ test byte [g_VectorDelta+r8*4+512], bl
+ jz .loop_continue
+
+ ;; if (IS_KNIGHT_OR_KING(p)) goto nothing_blocks
+ and ecx, 3
+ cmp ecx, 2
+ mov ecx, c
+ je .nothing_blocks
+
+ ;;
+ ;; Not a knight or king. Check to see if there is a piece in
+ ;; the path from cSquare to c that blocks the attack.
+ ;;
+ movsx ebx, byte [g_VectorDelta+r8*4+515]
+ mov eax, cSquareSave
+.block_loop:
+ add eax, ebx
+ cmp eax, ecx
+ je .nothing_blocks
+ movsxd rdx, eax
+ cmp dword [rsi+rdx*8], 0
+ jne .loop_continue
+ jmp .block_loop
+
+.nothing_blocks:
+ mov dword [rdi], r9d
+ mov dword [rdi+4], ecx
+
+ ;; index into g_PieceData: sizeof(PIECE_DATA) is 24 on x64 (not
+ ;; 16, as on x86) because its trailing "CHAR *szName" widens
+ ;; from 4 to 8 bytes and pads the struct to 8-byte alignment.
+ mov ecx, r9d
+ shr ecx, 1
+ imul ecx, ecx, 24
+ movsxd rcx, ecx
+ mov ebx, dword [g_PieceData+rcx]
+ mov dword [rdi+8], ebx
+
+ mov rax, pOldList
+ add rdi, 12
+ add dword [rax], 1
+ jmp .loop_continue
+
+.done: add rsp, 0x20
+ pop rbx
+ pop rbp
+ ret
%endif ; !CROUTINES
[GLOBAL LockCompareExchange]
[GLOBAL _LockCompareExchange]
-%define uComp esp+0xC
-%define uExch esp+8
-%define pDest esp+4
- ;;
+ ;;
;; ULONG CDECL
- ;; LockCompareExchange(void *dest, ; esp + 4
- ;; ULONG exch, ; esp + 8
- ;; ULONG comp) ; esp + C
- ;;
+ ;; LockCompareExchange(void *dest, ; rdi (SysV AMD64 ABI)
+ ;; ULONG exch, ; esi
+ ;; ULONG comp) ; edx
+ ;;
LockCompareExchange:
_LockCompareExchange:
- mov ecx, [pDest]
- mov edx, [uExch]
- mov eax, [uComp]
- lock cmpxchg dword [ecx], edx
+ mov eax, edx ; comp -> eax (cmpxchg's implicit compare reg)
+ mov rcx, rdi ; dest pointer -> rcx
+ lock cmpxchg dword [rcx], esi
ret
int 3
@@ -147,13 +284,13 @@ _LockCompareExchange:
[GLOBAL _LockIncrement]
;;
;; ULONG CDECL
- ;; LockIncrement(ULONG *pDest)
- ;;
+ ;; LockIncrement(ULONG *pDest) ; rdi (SysV AMD64 ABI)
+ ;;
LockIncrement:
_LockIncrement:
- mov ecx, [pDest]
+ mov rcx, rdi
mov eax, 1
- lock xadd [ecx], eax
+ lock xadd [rcx], eax
add eax, 1
ret
int 3
@@ -162,13 +299,13 @@ _LockIncrement:
[GLOBAL _LockDecrement]
;;
;; ULONG CDECL
- ;; LockDecrement(ULONG *pDest)
- ;;
+ ;; LockDecrement(ULONG *pDest) ; rdi (SysV AMD64 ABI)
+ ;;
LockDecrement:
_LockDecrement:
- mov ecx, [pDest]
+ mov rcx, rdi
mov eax, -1
- lock xadd [ecx], eax
+ lock xadd [rcx], eax
add eax, -1
ret
int 3