// File: SethKasmann[P]clever-girl/src/move_generator.cpp
// Function: void MoveList::pushPawnMoves<(MoveType)2, (Color)1>()
void MoveList::pushPawnMoves()
{
    constexpr int U = C == white ? 8 : -8;
    constexpr int L = C == white ? 9 : -7;
    constexpr int R = C == white ? 7 : -9;

    U64 promo, pawns;
    Square dst;

    pawns = mState.getPieceBB<pawn>(C);

    promo = (C == white ? pawns << 8 : pawns >> 8) & RankPromo;

    while (promo)
    {
        dst = pop_lsb(promo);
        pushPromotion<T>(dst - U, dst);
    }

    if (T == MoveType::Attacks || T == MoveType::Evasions || T == MoveType::All)
    {
        U64 occ = ((T == MoveType::Evasions ? mState.getOccupancyBB(!C) & mValid
                                            : mState.getOccupancyBB(!C))
                  | mState.getEnPassantBB()) & ~RankPromo;

        U64 left  = C == white ? (pawns & Not_a_file) << 9 & occ 
                               : (pawns & Not_a_file) >> 7 & occ;
        U64 right = C == white ? (pawns & Not_h_file) << 7 & occ
                               : (pawns & Not_h_file) >> 9 & occ;

        while (left)
        {
            dst = pop_lsb(left);
            push(makeMove(dst - L, dst));
        }

        while (right)
        {
            dst = pop_lsb(right);
            push(makeMove(dst - R, dst));
        }
    }

    if (T != MoveType::Attacks)
    {
        U64 empty = mState.getEmptyBB() & ~RankPromo;

        U64 up  = (C == white ? pawns << 8 : pawns >> 8) & empty;
        U64 dbl = (C == white ? (up & Rank_3) << 8 
                              : (up & Rank_6) >> 8) & empty;

        if (T == MoveType::Evasions)
        {
            up  &= mValid;
            dbl &= mValid;
        }

        if (T == MoveType::QuietChecks)
        {
            U64 dis;

            up  &= mState.getCheckSquaresBB(pawn);
            dbl &= mState.getCheckSquaresBB(pawn);

            dis = mDiscover & pawns & ~file_bb[mState.getKingSquare(!C)];
            dis = (C == white ? dis << 8 : dis >> 8) & empty;
            up  |= dis;
            dbl |= (C == white ? (dis & Rank_3) << 8 
                               : (dis & Rank_6) >> 8) & empty;
        }

        while (up)
        {
            dst = pop_lsb(up);
            push(makeMove(dst - U, dst));
        }

        while (dbl)
        {
            dst = pop_lsb(dbl);
            push(makeMove(dst - U - U, dst));
        }
    }
}

// Assembly:
subq $0x78, %rsp
movq %rdi, 0x70(%rsp)
movq 0x70(%rsp), %rax
movq %rax, 0x10(%rsp)
movl $0xfffffff8, 0x6c(%rsp) # imm = 0xFFFFFFF8
movl $0xfffffff9, 0x68(%rsp) # imm = 0xFFFFFFF9
movl $0xfffffff7, 0x64(%rsp) # imm = 0xFFFFFFF7
movq 0x18(%rax), %rdi
movl $0x1, %esi
callq 0x24b80
movq %rax, 0x50(%rsp)
movq 0x50(%rsp), %rax
shrq $0x8, %rax
movabsq $-0xffffffffffff01, %rcx # imm = 0xFF000000000000FF
andq %rcx, %rax
movq %rax, 0x58(%rsp)
cmpq $0x0, 0x58(%rsp)
je 0x28b8f
leaq 0x58(%rsp), %rdi
callq 0x25770
movl %eax, 0x4c(%rsp)
movl 0x4c(%rsp), %edi
movl $0xfffffff8, %esi       # imm = 0xFFFFFFF8
callq 0x24e80
movq 0x10(%rsp), %rdi
movl %eax, %esi
movl 0x4c(%rsp), %edx
callq 0x2a7d0
jmp 0x28b59
movq 0x10(%rsp), %rax
movq 0x18(%rax), %rax
movq %rax, (%rsp)
movl $0x1, %edi
callq 0x24ce0
movq (%rsp), %rdi
movl %eax, %esi
callq 0x25740
movq %rax, %rcx
movq 0x10(%rsp), %rax
andq 0x8(%rax), %rcx
movq %rcx, 0x8(%rsp)
movq 0x18(%rax), %rdi
callq 0x2abd0
movq %rax, %rcx
movq 0x8(%rsp), %rax
orq %rcx, %rax
movabsq $0xffffffffffff00, %rcx # imm = 0xFFFFFFFFFFFF00
andq %rcx, %rax
movq %rax, 0x40(%rsp)
movabsq $0x7f7f7f7f7f7f7f7f, %rax # imm = 0x7F7F7F7F7F7F7F7F
andq 0x50(%rsp), %rax
shrq $0x7, %rax
andq 0x40(%rsp), %rax
movq %rax, 0x38(%rsp)
movabsq $-0x101010101010102, %rax # imm = 0xFEFEFEFEFEFEFEFE
andq 0x50(%rsp), %rax
shrq $0x9, %rax
andq 0x40(%rsp), %rax
movq %rax, 0x30(%rsp)
cmpq $0x0, 0x38(%rsp)
je 0x28c60
leaq 0x38(%rsp), %rdi
callq 0x25770
movl %eax, 0x4c(%rsp)
movl 0x4c(%rsp), %edi
movl $0xfffffff9, %esi       # imm = 0xFFFFFFF9
callq 0x24e80
movl %eax, %edi
movl 0x4c(%rsp), %esi
callq 0x2a7b0
movq 0x10(%rsp), %rdi
movzwl %ax, %esi
callq 0x26df0
jmp 0x28c22
jmp 0x28c62
cmpq $0x0, 0x30(%rsp)
je 0x28ca0
leaq 0x30(%rsp), %rdi
callq 0x25770
movl %eax, 0x4c(%rsp)
movl 0x4c(%rsp), %edi
movl $0xfffffff7, %esi       # imm = 0xFFFFFFF7
callq 0x24e80
movl %eax, %edi
movl 0x4c(%rsp), %esi
callq 0x2a7b0
movq 0x10(%rsp), %rdi
movzwl %ax, %esi
callq 0x26df0
jmp 0x28c62
movq 0x10(%rsp), %rax
movq 0x18(%rax), %rdi
callq 0x24ef0
movq %rax, %rcx
movq 0x10(%rsp), %rax
movabsq $0xffffffffffff00, %rdx # imm = 0xFFFFFFFFFFFF00
andq %rdx, %rcx
movq %rcx, 0x28(%rsp)
movq 0x50(%rsp), %rcx
shrq $0x8, %rcx
andq 0x28(%rsp), %rcx
movq %rcx, 0x20(%rsp)
movabsq $0xff0000000000, %rcx   # imm = 0xFF0000000000
andq 0x20(%rsp), %rcx
shrq $0x8, %rcx
andq 0x28(%rsp), %rcx
movq %rcx, 0x18(%rsp)
movq 0x8(%rax), %rcx
andq 0x20(%rsp), %rcx
movq %rcx, 0x20(%rsp)
movq 0x8(%rax), %rax
andq 0x18(%rsp), %rax
movq %rax, 0x18(%rsp)
cmpq $0x0, 0x20(%rsp)
je 0x28d52
leaq 0x20(%rsp), %rdi
callq 0x25770
movl %eax, 0x4c(%rsp)
movl 0x4c(%rsp), %edi
movl $0xfffffff8, %esi       # imm = 0xFFFFFFF8
callq 0x24e80
movl %eax, %edi
movl 0x4c(%rsp), %esi
callq 0x2a7b0
movq 0x10(%rsp), %rdi
movzwl %ax, %esi
callq 0x26df0
jmp 0x28d14
jmp 0x28d54
cmpq $0x0, 0x18(%rsp)
je 0x28d9e
leaq 0x18(%rsp), %rdi
callq 0x25770
movl %eax, 0x4c(%rsp)
movl 0x4c(%rsp), %edi
movl $0xfffffff8, %esi       # imm = 0xFFFFFFF8
callq 0x24e80
movl %eax, %edi
movl $0xfffffff8, %esi       # imm = 0xFFFFFFF8
callq 0x24e80
movl %eax, %edi
movl 0x4c(%rsp), %esi
callq 0x2a7b0
movq 0x10(%rsp), %rdi
movzwl %ax, %esi
callq 0x26df0
jmp 0x28d54
addq $0x78, %rsp
retq
nopw %cs:(%rax,%rax)
nopl (%rax)