// File: /workspace/github_c_makefile_star2_O3/johnvtan[P]ccccc/asm.c
// Function: stmt_to_instrs
static list_t *stmt_to_instrs(stmt_t *stmt, context_t context) {
    if (!stmt) {
        UNREACHABLE("stmt_to_instrs: stmt is invalid\n");
    }
    
    if (stmt->type == STMT_NULL) {
        return list_new();
    }

    if (stmt->type == STMT_RETURN) {
        list_t *ret = list_new();
        debug("Found return statement\n");
        list_t *expr_instrs = expr_to_instrs(stmt->ret->expr, context.env);
        list_concat(ret, expr_instrs);
        list_push(ret, instr_label(OP_JMP, context.return_label));
        return ret;
    }

    if (stmt->type == STMT_BREAK) {
        list_t *ret = list_new();
        list_push(ret, instr_label(OP_JMP, context.iter_break_label));
        return ret;
    }

    if (stmt->type == STMT_CONTINUE) {
        list_t *ret = list_new();
        list_push(ret, instr_label(OP_JMP, context.iter_continue_label));
        return ret;
    }

    if (stmt->type == STMT_IF) {
        debug("Found if statement\n");
        list_t *ret = list_new();
        
        list_concat(ret, expr_to_instrs(stmt->if_stmt->cond, context.env));
        list_push(ret, instr_i2r(OP_CMP, 0, REG_RAX));

        string_t *post_cond_label = unique_label("post_cond");
        output_t *post_cond_label_output = new_label(post_cond_label, LABEL_STATIC);
        list_t *then_instrs = block_or_single_to_instrs(stmt->if_stmt->then, context);

        if (stmt->if_stmt->els) {
            string_t *else_label = unique_label("else");
            list_push(ret, instr_label(OP_JE, else_label));
            list_concat(ret, then_instrs);
            list_push(ret, instr_label(OP_JMP, post_cond_label));
            list_push(ret, new_label(else_label, LABEL_STATIC));
            list_concat(ret, block_or_single_to_instrs(stmt->if_stmt->els, context));
            list_push(ret, post_cond_label_output);
        } else {
            // No else statement, just emit the then instructions
            list_push(ret, instr_label(OP_JE, post_cond_label));
            list_concat(ret, then_instrs);
            list_push(ret, post_cond_label_output);
        }
        return ret;
    }

    if (stmt->type == STMT_BLOCK) {
        debug("Found block statement\n");
        return block_to_instrs(stmt->block, context);
    }

    if (stmt->type == STMT_DECLARE) {
        debug("Found a declare statement for var %s\n", string_get(stmt->declare->name));

        // only check if the variable is declared in this scope.
        var_info_t *var_info = map_get(context.env->homes, stmt->declare->name);
        if (var_info->declared) {
            UNREACHABLE("Compilation error: variable has multiple definitions in the same scope");
        }

        debug("Set declared for var\n");
        var_info->declared = true;
        if (stmt->declare->init_expr) {
            list_t *ret = list_new();
            list_concat(ret, expr_to_instrs(stmt->declare->init_expr, context.env));

            // expr should be in rax, so move it to the variable home.
            output_t *mov = instr_r2m(OP_MOV, REG_RAX, var_info->home);
            list_push(ret, mov);
            return ret;
        }
        return list_new();
    }

    if (stmt->type == STMT_EXPR) {
        list_t *ret = list_new();
        debug("Found an expr statement\n");
        list_t *expr_instrs = expr_to_instrs(stmt->expr, context.env);
        if (!expr_instrs) {
            UNREACHABLE("expr_instrs is invalid")
        }
        list_concat(ret, expr_instrs);
        return ret;
    }

    if (stmt->type == STMT_FOR) {
        string_t *begin_for_label = unique_label("begin_for");
        string_t *post_for_label = unique_label("end_for");
        string_t *post_body_label = unique_label("post_for_body");

        context.env = stmt->for_stmt->env;
        context.iter_continue_label = post_body_label;
        context.iter_break_label = post_for_label;

        list_t *ret = list_new();
        list_concat(ret, stmt_to_instrs(stmt->for_stmt->init, context));

        list_push(ret, new_label(begin_for_label, LABEL_STATIC));
        list_concat(ret, expr_to_instrs(stmt->for_stmt->cond, context.env));
        list_push(ret, instr_i2r(OP_CMP, 0, REG_RAX));
        list_push(ret, instr_label(OP_JE, post_for_label));

        list_concat(ret, block_or_single_to_instrs(stmt->for_stmt->body, context));
        list_push(ret, new_label(post_body_label, LABEL_STATIC));

        list_concat(ret, expr_to_instrs(stmt->for_stmt->post, context.env));
        list_push(ret, instr_label(OP_JMP, begin_for_label));
        list_push(ret, new_label(post_for_label, LABEL_STATIC));
        return ret;
    }

    if (stmt->type == STMT_WHILE) {
        list_t *ret = list_new();
        string_t *begin_while_label = unique_label("begin_while");
        string_t *post_while_label = unique_label("post_while");
        context.iter_continue_label = begin_while_label;
        context.iter_break_label = post_while_label;

        list_push(ret, new_label(begin_while_label, LABEL_STATIC));

        list_concat(ret, expr_to_instrs(stmt->while_stmt->cond, context.env));

        list_push(ret, instr_i2r(OP_CMP, 0, REG_RAX));
        list_push(ret, instr_label(OP_JE, post_while_label));

        list_concat(ret, block_or_single_to_instrs(stmt->while_stmt->body, context));
        list_push(ret, instr_label(OP_JMP, begin_while_label));
        list_push(ret, new_label(post_while_label, LABEL_STATIC));

        return ret;
    }

    if (stmt->type == STMT_DO) {
        list_t *ret = list_new();
        string_t *begin_do_label = unique_label("begin_do");
        string_t *end_do_label = unique_label("end_do");

        context.iter_continue_label = begin_do_label;
        context.iter_break_label = end_do_label;
        list_push(ret, new_label(begin_do_label, LABEL_STATIC));
        list_concat(ret, block_or_single_to_instrs(stmt->do_stmt->body, context));
        list_concat(ret, expr_to_instrs(stmt->do_stmt->cond, context.env));
        list_push(ret, instr_i2r(OP_CMP, 0, REG_RAX));
        list_push(ret, instr_label(OP_JNE, begin_do_label));
        list_push(ret, new_label(end_do_label, LABEL_STATIC));
        return ret;
    }

    UNREACHABLE("Unrecognized statement type\n");
    return NULL;
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x28, %rsp
testq %rdi, %rdi
je 0x1dc4
movq %rdi, %r14
movl (%rdi), %eax
cmpq $0xa, %rax
ja 0x1e27
leaq 0x60(%rsp), %r13
leaq 0x4841(%rip), %rcx      # 0x6020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
callq 0x2ea0
movq %rax, %rbx
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movq (%r13), %rsi
jmp 0x1c88
callq 0x2ea0
movq %rax, %rbx
movq 0x8(%r14), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
testq %rax, %rax
je 0x1def
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
jmp 0x1d87
callq 0x2ea0
movq %rax, %rbx
movq 0x10(%r13), %rsi
jmp 0x1c88
callq 0x2ea0
movq %rax, %rbx
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x4, %edi
xorl %esi, %esi
movl $0x1, %edx
callq 0x200e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
leaq 0x4a09(%rip), %rdi      # 0x62a2
callq 0x1734
movq %rax, %r12
movl $0x40, %edi
callq 0x10e0
movq %rax, %r15
movl $0x1, (%rax)
movq %r12, 0x8(%rax)
movl $0x0, 0x10(%rax)
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x2cd2
movq %rax, %rbp
movq 0x8(%r14), %rax
cmpq $0x0, 0x10(%rax)
je 0x1d99
leaq 0x49b4(%rip), %rdi      # 0x62ac
callq 0x1734
movq %rbp, 0x20(%rsp)
movq %rax, %rbp
movl $0x15, %edi
movq %rax, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq %rbx, %rdi
movq 0x20(%rsp), %rsi
callq 0x2f51
movl $0x14, %edi
movq %r12, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movl $0x40, %edi
callq 0x10e0
movl $0x1, (%rax)
movq %rbp, 0x8(%rax)
movl $0x0, 0x10(%rax)
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x2cd2
movq %rbx, %rdi
movq %rax, %rsi
jmp 0x1db7
movq 0x8(%r14), %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2d3d
callq 0x2ea0
movq %rax, %rbx
leaq 0x4976(%rip), %rdi      # 0x632f
callq 0x1734
movq %rax, %r12
leaq 0x4973(%rip), %rdi      # 0x633b
callq 0x1734
movq %rax, %r15
movq %r12, 0x8(%r13)
movq %rax, 0x10(%r13)
movl $0x40, %edi
callq 0x10e0
movl $0x1, %ecx
movl %ecx, (%rax)
movq %r12, 0x8(%rax)
xorl %ebp, %ebp
movl %ebp, 0x10(%rax)
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x4, %edi
xorl %esi, %esi
movl $0x1, %edx
callq 0x200e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movl $0x15, %edi
movq %r15, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x2cd2
jmp 0x1c67
movq 0x18(%r13), %r12
movq (%r12), %rdi
movq 0x8(%r14), %rax
movq 0x8(%rax), %rsi
callq 0x3183
cmpb $0x1, 0x18(%rax)
je 0x1e0b
movq %rax, %r15
movb $0x1, 0x18(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %r13
callq 0x2ea0
movq %rax, %rbx
testq %r13, %r13
je 0x1d87
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movq %r12, %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl 0x8(%r15), %ebp
movq 0x10(%r15), %r14
movl $0x40, %edi
callq 0x10e0
xorl %ecx, %ecx
movl %ecx, (%rax)
movabsq $0x200000001, %rdx      # imm = 0x200000001
movq %rdx, 0x8(%rax)
movl %ecx, 0x10(%rax)
movl $0x1, %ecx
movl %ecx, 0x18(%rax)
movl %ecx, 0x28(%rax)
movl %ebp, 0x30(%rax)
movq %r14, 0x38(%rax)
jmp 0x1d7c
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2ea0
leaq 0x47ec(%rip), %rdi      # 0x630f
callq 0x1734
movq %rax, %r12
leaq 0x47e7(%rip), %rdi      # 0x6319
callq 0x1734
movq %rax, %r15
leaq 0x47e0(%rip), %rdi      # 0x6321
callq 0x1734
movq %rax, %rbp
movq 0x8(%r14), %rax
movq 0x20(%rax), %rax
movq %rax, 0x18(%r13)
movq %rbp, 0x8(%r13)
movq %r15, 0x10(%r13)
callq 0x2ea0
movq %rax, %rbx
movq 0x8(%r14), %rax
movq (%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x17ad
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x40, %edi
callq 0x10e0
movl $0x1, %ecx
movl %ecx, (%rax)
movq %r12, 0x8(%rax)
xorl %ecx, %ecx
movl %ecx, 0x10(%rax)
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x4, %edi
xorl %esi, %esi
movl $0x1, %edx
callq 0x200e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movl $0x15, %edi
movq %r15, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x18(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x2cd2
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x40, %edi
callq 0x10e0
movl $0x1, %ecx
movl %ecx, (%rax)
movq %rbp, 0x8(%rax)
xorl %ecx, %ecx
movl %ecx, 0x10(%rax)
xorl %ebp, %ebp
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x14, %edi
jmp 0x1d51
callq 0x2ea0
movq %rax, %rbx
movq 0x8(%r13), %rsi
movl $0x14, %edi
callq 0x2c45
jmp 0x1d7c
callq 0x2ea0
movq %rax, %rbx
leaq 0x46a0(%rip), %rdi      # 0x6346
callq 0x1734
movq %rax, %r12
leaq 0x469a(%rip), %rdi      # 0x634f
callq 0x1734
movq %rax, %r15
movq %r12, 0x8(%r13)
movq %rax, 0x10(%r13)
movl $0x40, %edi
callq 0x10e0
movl $0x1, %ecx
movl %ecx, (%rax)
movq %r12, 0x8(%rax)
xorl %ebp, %ebp
movl %ebp, 0x10(%rax)
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x2cd2
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x20bc
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f51
movl $0x4, %edi
xorl %esi, %esi
movl $0x1, %edx
callq 0x200e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movl $0x16, %edi
movq %r12, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movl $0x40, %edi
callq 0x10e0
movl $0x1, %ecx
movl %ecx, (%rax)
movq %r15, 0x8(%rax)
movl %ebp, 0x10(%rax)
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq %rbx, %rax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movl $0x15, %edi
movq %r12, %rsi
callq 0x2c45
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2f0b
movq %rbx, %rdi
movq %rbp, %rsi
callq 0x2f51
movq %rbx, %rdi
movq %r15, %rsi
jmp 0x1d82
leaq 0x4369(%rip), %rdi      # 0x6134
leaq 0x439c(%rip), %rsi      # 0x616e
leaq 0x44a8(%rip), %rcx      # 0x6281
movl $0x288, %edx            # imm = 0x288
xorl %eax, %eax
callq 0x1080
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x1110
leaq 0x433e(%rip), %rdi      # 0x6134
leaq 0x4371(%rip), %rsi      # 0x616e
leaq 0x44f4(%rip), %rcx      # 0x62f8
movl $0x2e1, %edx            # imm = 0x2E1
jmp 0x1dde
leaq 0x4322(%rip), %rdi      # 0x6134
leaq 0x4355(%rip), %rsi      # 0x616e
leaq 0x4491(%rip), %rcx      # 0x62b1
movl $0x2cb, %edx            # imm = 0x2CB
jmp 0x1dde
leaq 0x4306(%rip), %rdi      # 0x6134
leaq 0x4339(%rip), %rsi      # 0x616e
leaq 0x451a(%rip), %rcx      # 0x6356
movl $0x326, %edx            # imm = 0x326
jmp 0x1dde