// File: /workspace/github_c_makefile_star2_O2/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 0x1c34
movq %rdi, %r14
movl (%rdi), %eax
cmpq $0xa, %rax
ja 0x1c95
leaq 0x60(%rsp), %r13
leaq 0x3920(%rip), %rcx      # 0x5020
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
callq 0x2c34
movq %rax, %rbx
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movq (%r13), %rsi
jmp 0x1b20
callq 0x2c34
movq %rax, %rbx
movq 0x8(%r14), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
testq %rax, %rax
je 0x1c5d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
jmp 0x1bf9
callq 0x2c34
movq %rax, %rbx
movq 0x10(%r13), %rsi
jmp 0x1b20
callq 0x2c34
movq %rax, %rbx
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
pushq $0x4
popq %rdi
pushq $0x1
popq %rdx
xorl %esi, %esi
callq 0x1e60
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
leaq 0x3b18(%rip), %rdi      # 0x52ce
callq 0x1653
movq %rax, %r12
movq %rax, %rdi
xorl %esi, %esi
callq 0x162d
movq %rax, %rbp
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x29e4
movq %rax, %r15
movq 0x8(%r14), %rax
cmpq $0x0, 0x10(%rax)
je 0x1c0b
leaq 0x3ad4(%rip), %rdi      # 0x52d8
callq 0x1653
movq %rbp, 0x20(%rsp)
movq %rax, %rbp
pushq $0x15
popq %rdi
movq %rax, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq %rbx, %rdi
movq %r15, %rsi
callq 0x2cbd
pushq $0x14
popq %rdi
movq %r12, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq %rbp, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x29e4
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movq %rbx, %rdi
movq 0x20(%rsp), %rsi
jmp 0x1bf4
movq 0x8(%r14), %rdi
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2a4f
callq 0x2c34
movq %rax, %rbx
leaq 0x3aa0(%rip), %rdi      # 0x535b
callq 0x1653
movq %rax, %r12
leaq 0x3a9d(%rip), %rdi      # 0x5367
callq 0x1653
movq %rax, %r15
movq %r12, 0x8(%r13)
movq %rax, 0x10(%r13)
movq %r12, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
pushq $0x4
popq %rdi
pushq $0x1
popq %rdx
xorl %esi, %esi
callq 0x1e60
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
pushq $0x15
popq %rdi
movq %r15, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x29e4
jmp 0x1b02
movq 0x18(%r13), %r12
movq (%r12), %rdi
movq 0x8(%r14), %rax
movq 0x8(%rax), %rsi
callq 0x2ed9
cmpb $0x1, 0x18(%rax)
je 0x1c79
movq %rax, %r15
movb $0x1, 0x18(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %r13
callq 0x2c34
movq %rax, %rbx
testq %r13, %r13
je 0x1bf9
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movq %r12, %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movl 0x8(%r15), %esi
movq 0x10(%r15), %rdx
pushq $0x1
popq %rdi
callq 0x1eff
jmp 0x1bee
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x2c34
leaq 0x3955(%rip), %rdi      # 0x533b
callq 0x1653
movq %rax, %r12
leaq 0x3950(%rip), %rdi      # 0x5345
callq 0x1653
movq %rax, %r15
leaq 0x3949(%rip), %rdi      # 0x534d
callq 0x1653
movq %rax, %rbp
movq 0x8(%r14), %rax
movq 0x20(%rax), %rax
movq %rax, 0x18(%r13)
movq %rbp, 0x8(%r13)
movq %r15, 0x10(%r13)
callq 0x2c34
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 0x16ce
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movq %r12, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
pushq $0x4
popq %rdi
pushq $0x1
popq %rdx
xorl %esi, %esi
callq 0x1e60
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
pushq $0x15
popq %rdi
movq %r15, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x18(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x29e4
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movq %rbp, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
pushq $0x14
jmp 0x1bd0
callq 0x2c34
movq %rax, %rbx
movq 0x8(%r13), %rsi
pushq $0x14
popq %rdi
callq 0x295e
jmp 0x1bee
callq 0x2c34
movq %rax, %rbx
leaq 0x3836(%rip), %rdi      # 0x5372
callq 0x1653
movq %rax, %r12
leaq 0x3830(%rip), %rdi      # 0x537b
callq 0x1653
movq %rax, %r15
movq %r12, 0x8(%r13)
movq %rax, 0x10(%r13)
movq %r12, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq 0x8(%r14), %rax
movq 0x8(%rax), %rdi
movups (%r13), %xmm0
movups 0x10(%r13), %xmm1
movups %xmm1, 0x10(%rsp)
movups %xmm0, (%rsp)
callq 0x29e4
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
movq 0x8(%r14), %rax
movq (%rax), %rdi
movq 0x18(%r13), %rsi
callq 0x1f3f
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2cbd
pushq $0x4
popq %rdi
pushq $0x1
popq %rdx
xorl %esi, %esi
callq 0x1e60
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
pushq $0x16
popq %rdi
movq %r12, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq %r15, %rdi
xorl %esi, %esi
callq 0x162d
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq %rbx, %rax
addq $0x28, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
pushq $0x15
popq %rdi
movq %r12, %rsi
callq 0x295e
movq %rbx, %rdi
movq %rax, %rsi
callq 0x2c7e
movq %rbx, %rdi
movq %r15, %rsi
callq 0x2cbd
movq %rbx, %rdi
movq %rbp, %rsi
jmp 0x1bf4
leaq 0x34f9(%rip), %rdi      # 0x5134
leaq 0x352c(%rip), %rsi      # 0x516e
leaq 0x3664(%rip), %rcx      # 0x52ad
movl $0x288, %edx            # imm = 0x288
xorl %eax, %eax
callq 0x1080
pushq $-0x1
popq %rdi
callq 0x1110
leaq 0x34d0(%rip), %rdi      # 0x5134
leaq 0x3503(%rip), %rsi      # 0x516e
leaq 0x36b2(%rip), %rcx      # 0x5324
movl $0x2e1, %edx            # imm = 0x2E1
jmp 0x1c4e
leaq 0x34b4(%rip), %rdi      # 0x5134
leaq 0x34e7(%rip), %rsi      # 0x516e
leaq 0x364f(%rip), %rcx      # 0x52dd
movl $0x2cb, %edx            # imm = 0x2CB
jmp 0x1c4e
leaq 0x3498(%rip), %rdi      # 0x5134
leaq 0x34cb(%rip), %rsi      # 0x516e
leaq 0x36d8(%rip), %rcx      # 0x5382
movl $0x326, %edx            # imm = 0x326
jmp 0x1c4e