// File: ATOMIC-LICHESS[P]ATOMKRAFT/movegen.cpp
// Function: MoveStack* (anonymous namespace)::generate_pawn_moves<(Color)0, (MoveType)4>(Position const&, MoveStack*, unsigned long, Square)
MoveStack* generate_pawn_moves(const Position& pos, MoveStack* mlist, Bitboard target, Square ksq) {
	NEW assert(pos.piece_count(WHITE, KING) && pos.piece_count(BLACK, KING));
	  	
    // Calculate our parametrized parameters at compile time, named
    // according to the point of view of white side.
    const Color    Them      = (Us == WHITE ? BLACK    : WHITE);
    const Bitboard TRank7BB  = (Us == WHITE ? Rank7BB  : Rank2BB);
    const Bitboard TRank3BB  = (Us == WHITE ? Rank3BB  : Rank6BB);
    const Square   TDELTA_N  = (Us == WHITE ? DELTA_N  : DELTA_S);
    const Square   TDELTA_NE = (Us == WHITE ? DELTA_NE : DELTA_SE);
    const Square   TDELTA_NW = (Us == WHITE ? DELTA_NW : DELTA_SW);

    Square to;
    Bitboard b1, b2, dc1, dc2, pawnPushes, emptySquares;
    Bitboard pawns = pos.pieces(PAWN, Us);
    Bitboard pawnsOn7 = pawns & TRank7BB;
    Bitboard enemyPieces = (Type == MV_CAPTURE ? target : pos.pieces_of_color(Them));

    // Pre-calculate pawn pushes before changing emptySquares definition
    if (Type != MV_CAPTURE)
    {
        emptySquares = (Type == MV_NON_CAPTURE ? target : pos.empty_squares());
        pawnPushes = move_pawns<TDELTA_N>(pawns & ~TRank7BB) & emptySquares;
    }

    if (Type == MV_EVASION)
    {
        emptySquares &= target; // Only blocking squares
        enemyPieces  &= target; // Capture only the checker piece
    }

    // Promotions and underpromotions
    if (pawnsOn7)
    {
        if (Type == MV_CAPTURE)
            emptySquares = pos.empty_squares();
        
        NEW // here stockfish clears the promotion pawns so they are not available 
        NEW // for following move generation
        NEW // since capture promotions are handled as normal captures we remove this
        OLD pawns &= ~TRank7BB;	
        OLD mlist = generate_promotions<Us, Type, TDELTA_NE>(pos, mlist, pawnsOn7, enemyPieces);
        OLD mlist = generate_promotions<Us, Type, TDELTA_NW>(pos, mlist, pawnsOn7, enemyPieces);
        mlist = generate_promotions<Us, Type, TDELTA_N >(pos, mlist, pawnsOn7, emptySquares);
    }

    // Standard captures
    if (Type == MV_CAPTURE || Type == MV_EVASION)
    {
        mlist = generate_pawn_captures<Type, TDELTA_NE>(mlist, pawns, enemyPieces);
        mlist = generate_pawn_captures<Type, TDELTA_NW>(mlist, pawns, enemyPieces);
    }

    // Single and double pawn pushes
    if (Type != MV_CAPTURE)
    {
        b1 = pawnPushes & emptySquares;
        b2 = move_pawns<TDELTA_N>(pawnPushes & TRank3BB) & emptySquares;

        if (Type == MV_CHECK)
        {
            // Consider only pawn moves which give direct checks
            b1 &= pos.attacks_from<PAWN>(ksq, Them);
            b2 &= pos.attacks_from<PAWN>(ksq, Them);

            // Add pawn moves which gives discovered check. This is possible only
            // if the pawn is not on the same file as the enemy king, because we
            // don't generate captures.
            if (pawns & target) // For CHECK type target is dc bitboard
            {
                dc1 = move_pawns<TDELTA_N>(pawns & target & ~file_bb(ksq)) & emptySquares;
                dc2 = move_pawns<TDELTA_N>(dc1 & TRank3BB) & emptySquares;

                b1 |= dc1;
                b2 |= dc2;
            }
        }
        SERIALIZE_MOVES_D(b1, -TDELTA_N);
        SERIALIZE_MOVES_D(b2, -TDELTA_N -TDELTA_N);
    }

    // En passant captures
    if ((Type == MV_CAPTURE || Type == MV_EVASION) && pos.ep_square() != SQ_NONE)
    {
        assert(Us != WHITE || square_rank(pos.ep_square()) == RANK_6);
        assert(Us != BLACK || square_rank(pos.ep_square()) == RANK_3);

        // An en passant capture can be an evasion only if the checking piece
        // is the double pushed pawn and so is in the target. Otherwise this
        // is a discovery check and we are forced to do otherwise.
        if (Type == MV_EVASION && !bit_is_set(target, pos.ep_square() - TDELTA_N))
            return mlist;

        b1 = pawns & pos.attacks_from<PAWN>(pos.ep_square(), Them);

        assert(b1 != EmptyBoardBB);

        while (b1)
        {
            to = pop_1st_bit(&b1);
            (*mlist++).move = make_ep_move(to, pos.ep_square());
        }
    }
    return mlist;
  }

// Assembly:
subq $0xb8, %rsp
movq %rdi, 0xa8(%rsp)
movq %rsi, 0xa0(%rsp)
movq %rdx, 0x98(%rsp)
movl %ecx, 0x94(%rsp)
movl $0x1, 0x90(%rsp)
movabsq $0xff000000000000, %rax # imm = 0xFF000000000000
movq %rax, 0x88(%rsp)
movq $0xff0000, 0x80(%rsp) # imm = 0xFF0000
movl $0x8, 0x7c(%rsp)
movl $0x9, 0x78(%rsp)
movl $0x7, 0x74(%rsp)
movq 0xa8(%rsp), %rdi
movl $0x1, %esi
xorl %edx, %edx
callq 0x16530
movq %rax, 0x38(%rsp)
movabsq $0xff000000000000, %rax # imm = 0xFF000000000000
andq 0x38(%rsp), %rax
movq %rax, 0x30(%rsp)
movq 0xa8(%rsp), %rdi
movl $0x1, %esi
callq 0x298c0
movq %rax, 0x28(%rsp)
movq 0xa8(%rsp), %rdi
callq 0x33220
movq %rax, 0x40(%rsp)
movabsq $-0xff000000000001, %rdi # imm = 0xFF00FFFFFFFFFFFF
andq 0x38(%rsp), %rdi
callq 0x30aa0
andq 0x40(%rsp), %rax
movq %rax, 0x48(%rsp)
movq 0x98(%rsp), %rax
andq 0x40(%rsp), %rax
movq %rax, 0x40(%rsp)
movq 0x98(%rsp), %rax
andq 0x28(%rsp), %rax
movq %rax, 0x28(%rsp)
cmpq $0x0, 0x30(%rsp)
je 0x31b7e
movq 0xa8(%rsp), %rdi
movq 0xa0(%rsp), %rsi
movq 0x30(%rsp), %rdx
movq 0x40(%rsp), %rcx
callq 0x32140
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rdi
movq 0x38(%rsp), %rsi
movq 0x28(%rsp), %rdx
callq 0x32270
movq %rax, 0xa0(%rsp)
movq 0xa0(%rsp), %rdi
movq 0x38(%rsp), %rsi
movq 0x28(%rsp), %rdx
callq 0x32320
movq %rax, 0xa0(%rsp)
movq 0x48(%rsp), %rax
andq 0x40(%rsp), %rax
movq %rax, 0x68(%rsp)
movq 0x48(%rsp), %rdi
andq $0xff0000, %rdi         # imm = 0xFF0000
callq 0x30aa0
andq 0x40(%rsp), %rax
movq %rax, 0x60(%rsp)
cmpq $0x0, 0x68(%rsp)
je 0x31c41
leaq 0x68(%rsp), %rdi
callq 0xd940
movl %eax, 0x70(%rsp)
movl 0x70(%rsp), %eax
movl %eax, 0x24(%rsp)
movl $0x8, %edi
callq 0x33a00
movl 0x24(%rsp), %edi
movl %eax, %esi
callq 0xd780
movl %eax, %edi
movl 0x70(%rsp), %esi
callq 0xf810
movl %eax, %ecx
movq 0xa0(%rsp), %rax
movq %rax, %rdx
addq $0x8, %rdx
movq %rdx, 0xa0(%rsp)
movl %ecx, (%rax)
jmp 0x31be6
jmp 0x31c43
cmpq $0x0, 0x60(%rsp)
je 0x31caa
leaq 0x60(%rsp), %rdi
callq 0xd940
movl %eax, 0x70(%rsp)
movl 0x70(%rsp), %eax
movl %eax, 0x20(%rsp)
movl $0x8, %edi
callq 0x33a00
movl %eax, %edi
movl $0x8, %esi
callq 0xe9c0
movl 0x20(%rsp), %edi
movl %eax, %esi
callq 0xd780
movl %eax, %edi
movl 0x70(%rsp), %esi
callq 0xf810
movl %eax, %ecx
movq 0xa0(%rsp), %rax
movq %rax, %rdx
addq $0x8, %rdx
movq %rdx, 0xa0(%rsp)
movl %ecx, (%rax)
jmp 0x31c43
movq 0xa8(%rsp), %rdi
callq 0xf5b0
cmpl $0x40, %eax
je 0x31da7
movq 0x98(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0xa8(%rsp), %rdi
callq 0xf5b0
movl %eax, %edi
movl $0x8, %esi
callq 0xe9c0
movq 0x18(%rsp), %rdi
movl %eax, %esi
callq 0xd760
cmpq $0x0, %rax
jne 0x31d0d
movq 0xa0(%rsp), %rax
movq %rax, 0xb0(%rsp)
jmp 0x31db7
movq 0x38(%rsp), %rax
movq %rax, 0x10(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0xa8(%rsp), %rdi
callq 0xf5b0
movq 0x8(%rsp), %rdi
movl %eax, %esi
movl $0x1, %edx
callq 0x1b460
movq %rax, %rcx
movq 0x10(%rsp), %rax
andq %rcx, %rax
movq %rax, 0x68(%rsp)
cmpq $0x0, 0x68(%rsp)
je 0x31da5
leaq 0x68(%rsp), %rdi
callq 0xd940
movl %eax, 0x70(%rsp)
movl 0x70(%rsp), %eax
movl %eax, 0x4(%rsp)
movq 0xa8(%rsp), %rdi
callq 0xf5b0
movl 0x4(%rsp), %edi
movl %eax, %esi
callq 0x33a10
movl %eax, %ecx
movq 0xa0(%rsp), %rax
movq %rax, %rdx
addq $0x8, %rdx
movq %rdx, 0xa0(%rsp)
movl %ecx, (%rax)
jmp 0x31d52
jmp 0x31da7
movq 0xa0(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0xb0(%rsp), %rax
addq $0xb8, %rsp
retq
nopw (%rax,%rax)