// File: /workspace/github_c_makefile_star2_O3/sharmaeklavya2[P]cerplag/codegen.c
// Function: codegen
void codegen(pAstNode p) {
    if(error_count == 0 && allow_codegen) {
        switch(p->base.node_type) {
            case ASTN_Module: {
                ModuleNode* q = (ModuleNode*)p;
                codegen_chain(q->body, &(q->base.ircode));
                break;
            }

            case ASTN_Var:
            case ASTN_Num:
            case ASTN_RNum:
            case ASTN_Bool:
                break;
            case ASTN_Decl:
            case ASTN_Deref:
                break;

            case ASTN_Assn: {
                AssnNode* q = (AssnNode*)p;
                ircode_copy(&(q->base.ircode), &(q->expr->base.ircode));
                ircode_append(&(q->base.ircode), irinstr_new2(OP_MOV, q->target->base.addr,
                    q->expr->base.addr, NULL));
                break;
            }
            case ASTN_BOp: {
                BOpNode* q = (BOpNode*)p;
                ircode_combine(&(q->base.ircode), &(q->arg1->base.ircode), &(q->arg2->base.ircode));
                ircode_append(&(q->base.ircode), irinstr_new2(q->op, q->base.addr,
                    q->arg1->base.addr, q->arg2->base.addr));
                break;
            }

            case ASTN_UOp: {
                UOpNode* q = (UOpNode*)p;
                ircode_copy(&(q->base.ircode), &(q->arg->base.ircode));
                ircode_append(&(q->base.ircode), irinstr_new2(OP_UMINUS, q->base.addr,
                    q->arg->base.addr, NULL));
                break;
            }
            case ASTN_Output: {
                OutputNode* q = (OutputNode*)p;
                ircode_append(&(q->base.ircode), irinstr_new2(OP_OUTPUT, NULL, q->var->base.addr, NULL));
                break;
            }
            case ASTN_Input: {
                InputNode* q = (InputNode*)p;
                ircode_append(&(q->base.ircode), irinstr_new2(OP_INPUT, q->base.addr, NULL, NULL));
                break;
            }
            case ASTN_For: {
                ForNode* q = (ForNode*)p;
                ircode_append(&(q->base.ircode), irinstr_new2(OP_MOV, q->base.addr, q->beg_addr, NULL));
                IRInstr* beg_instr = irinstr_new3(OP_LABEL, label_counter++);
                IRInstr* end_instr = irinstr_new3(OP_LABEL, label_counter++);
                IRInstr* break_instr = irinstr_new4(OP_JG, NULL, q->base.addr,
                    q->end_addr, end_instr->label);
                IRInstr* loop_instr = irinstr_new3(OP_JUMP, beg_instr->label);

                ircode_append(&(q->base.ircode), beg_instr);
                ircode_append(&(q->base.ircode), break_instr);
                codegen_chain(q->body, &(q->base.ircode));
                ircode_append(&(q->base.ircode), irinstr_new2(OP_INC, q->base.addr, NULL, NULL));
                ircode_append(&(q->base.ircode), loop_instr);
                ircode_append(&(q->base.ircode), end_instr);
                break;
            }
            case ASTN_While: {
                WhileNode* q = (WhileNode*)p;
                IRInstr* beg_instr = irinstr_new3(OP_LABEL, label_counter++);
                IRInstr* end_instr = irinstr_new3(OP_LABEL, label_counter++);
                IRInstr* break_instr = irinstr_new4(OP_JUMP0, NULL, q->cond->base.addr, NULL, end_instr->label);
                IRInstr* loop_instr = irinstr_new3(OP_JUMP, beg_instr->label);

                ircode_append(&(q->base.ircode), beg_instr);
                ircode_combine(&(q->base.ircode), &(q->base.ircode), &(q->cond->base.ircode));
                ircode_append(&(q->base.ircode), break_instr);
                codegen_chain(q->body, &(q->base.ircode));
                ircode_append(&(q->base.ircode), loop_instr);
                ircode_append(&(q->base.ircode), end_instr);
                break;
            }
            case ASTN_Switch: {
                SwitchNode* q = (SwitchNode*)p;
                CaseNode* node;
                if(q->base.addr->type == TYPE_BOOLEAN) {
                    pAstNode true_stmts=NULL, false_stmts=NULL;
                    for(node = q->cases; node != NULL; node = node->next) {
                        bool val = ((BoolNode*)(node->val))->val;
                        if(val) true_stmts = node->stmts;
                        else false_stmts = node->stmts;
                    }
                    IRInstr* label1 = irinstr_new3(OP_LABEL, label_counter++);
                    IRInstr* label2 = irinstr_new3(OP_LABEL, label_counter++);
                    ircode_append(&(q->base.ircode), irinstr_new4(OP_JUMP0,
                        NULL, q->base.addr, NULL, label1->label));
                    codegen_chain(true_stmts, &(q->base.ircode));
                    ircode_append(&(q->base.ircode), irinstr_new3(OP_JUMP, label2->label));
                    ircode_append(&(q->base.ircode), label1);
                    codegen_chain(false_stmts, &(q->base.ircode));
                    ircode_append(&(q->base.ircode), label2);
                }
                else {
                    IRInstr* exit_label = irinstr_new3(OP_LABEL, label_counter++);
                    for(node = q->cases; node != NULL; node = node->next) {
                        IRInstr* label = irinstr_new3(OP_LABEL, label_counter++);
                        ircode_append(&(q->base.ircode), irinstr_new4(OP_JNE,
                            NULL, q->base.addr, node->val->base.addr, label->label));
                        codegen_chain(node->stmts, &(q->base.ircode));
                        ircode_append(&(q->base.ircode), irinstr_new3(OP_JUMP, exit_label->label));
                        ircode_append(&(q->base.ircode), irinstr_new3(OP_LABEL, label->label));
                    }
                    if(q->defaultcase != NULL) {
                        codegen_chain(q->defaultcase->stmts, &(q->base.ircode));
                    }
                    ircode_append(&(q->base.ircode), irinstr_new3(OP_LABEL, exit_label->label));
                }
                break;
            }
            default:
                complain_ast_node_type(__func__, p->base.node_type);
        }
    }
    if(error_count > 0) {
        switch(p->base.node_type) {
            case ASTN_BOp:
                ircode_clear(&(((BOpNode*)p)->arg1->base.ircode));
                ircode_clear(&(((BOpNode*)p)->arg2->base.ircode));
                break;
            case ASTN_UOp:
                ircode_clear(&(((UOpNode*)p)->arg->base.ircode));
                break;
            case ASTN_Deref:
                ircode_clear(&(((DerefNode*)p)->index->base.ircode));
                break;
            case ASTN_Module:
                destroy_code_chain(((ModuleNode*)p)->body);
                break;
            case ASTN_Assn:
                ircode_clear(&(((AssnNode*)p)->target->base.ircode));
                ircode_clear(&(((AssnNode*)p)->expr->base.ircode));
                break;
            case ASTN_While:
                ircode_clear(&(((WhileNode*)p)->cond->base.ircode));
                ircode_clear(&(((WhileNode*)p)->body->base.ircode));
                break;
            case ASTN_For:
                ircode_clear(&(((ForNode*)p)->body->base.ircode));
                break;
            case ASTN_Decl:
                destroy_code_chain((pAstNode)(((DeclNode*)p)->idList));
                break;
            case ASTN_Output:
                ircode_clear(&(((OutputNode*)p)->var->base.ircode));
                break;
            case ASTN_FCall:
                destroy_code_chain((pAstNode)(((FCallNode*)p)->iParamList));
                destroy_code_chain((pAstNode)(((FCallNode*)p)->oParamList));
                break;
            case ASTN_Switch: {
                SwitchNode* q = (SwitchNode*)p;
                if(q->defaultcase != NULL) {
                    ircode_clear(&(q->defaultcase->val->base.ircode));
                    destroy_code_chain(q->defaultcase->stmts);
                }
                CaseNode* node = q->cases;
                while(node != NULL) {
                    destroy_code_chain(node->stmts);
                    ircode_clear(&(node->val->base.ircode));
                    node = node->next;
                }
                break;
            }
            default:
                break;
        }
    }
    /*
    fprintf(stderr, "codegen on node(%s, %d:%d):\n", ASTN_STRS[p->base.node_type], p->base.line, p->base.col);
    ircode_print(&(p->base.ircode), stderr);
    */
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x18, %rsp
movq %rdi, %rbx
leaq 0xd6c1(%rip), %r13      # 0x1adb8
movl (%r13), %eax
testl %eax, %eax
jne 0xd9f4
cmpb $0x1, 0x8616(%rip)      # 0x15d20
jne 0xda6b
movl (%rbx), %esi
cmpq $0x12, %rsi
ja 0xd854
leaq 0x27c5(%rip), %rax      # 0xfee8
movslq (%rax,%rsi,4), %rcx
addq %rax, %rcx
jmpq *%rcx
leaq 0x20(%rbx), %r14
movq 0x38(%rbx), %rsi
movq 0x40(%rbx), %rdx
addq $0x20, %rsi
addq $0x20, %rdx
movq %r14, %rdi
callq 0xc383
movl 0x48(%rbx), %edi
movq 0x18(%rbx), %rsi
movq 0x38(%rbx), %rax
movq 0x18(%rax), %rdx
movq 0x40(%rbx), %rax
movq 0x18(%rax), %rcx
jmp 0xd9e0
leaq 0x20(%rbx), %r14
movq 0x18(%rbx), %rsi
movl $0xf, %edi
xorl %edx, %edx
jmp 0xd9de
leaq 0x20(%rbx), %r14
movq 0x18(%rbx), %rsi
movq 0x50(%rbx), %rdx
movl $0xc, %edi
xorl %ecx, %ecx
callq 0xc084
movq %r14, %rdi
movq %rax, %rsi
callq 0xc40e
movl 0x8583(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x857a(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, %r15
movl 0x8567(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x855e(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, -0x30(%rbp)
movq 0x18(%rbx), %rdx
movq 0x58(%rbx), %rcx
movl 0x30(%rax), %r8d
movl $0x11, %edi
xorl %esi, %esi
callq 0xc0ff
movq %rax, %r12
movl 0x30(%r15), %esi
movl $0x10, %edi
callq 0xc0cb
movq %rax, -0x38(%rbp)
movq %r14, %rdi
movq %r15, %rsi
callq 0xc40e
movq %r14, %rdi
movq %r12, %rsi
callq 0xc40e
movq 0x60(%rbx), %rdi
movq %r14, %rsi
callq 0xd678
movq 0x18(%rbx), %rsi
movl $0x16, %edi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0xc084
movq %r14, %rdi
movq %rax, %rsi
callq 0xc40e
movq %r14, %rdi
movq -0x38(%rbp), %rsi
callq 0xc40e
movq %r14, %rdi
jmp 0xd9c5
leaq 0x2609(%rip), %rdi      # 0xfe64
callq 0x7a6c
jmp 0xd9f0
leaq 0x20(%rbx), %r14
movq 0x38(%rbx), %rsi
addq $0x20, %rsi
movq %r14, %rdi
callq 0xc369
movq 0x18(%rbx), %rsi
movq 0x38(%rbx), %rax
movq 0x18(%rax), %rdx
movl $0xd, %edi
jmp 0xd9de
leaq 0x20(%rbx), %r14
movq 0x48(%rbx), %rsi
addq $0x20, %rsi
movq %r14, %rdi
callq 0xc369
movq 0x40(%rbx), %rax
movq 0x48(%rbx), %rcx
movq 0x18(%rax), %rsi
movq 0x18(%rcx), %rdx
movl $0xc, %edi
jmp 0xd9de
movq 0x58(%rbx), %rdi
leaq 0x20(%rbx), %rsi
callq 0xd678
jmp 0xd9f0
movq 0x18(%rbx), %rax
cmpl $0x3, 0x18(%rax)
jne 0xdada
movq 0x50(%rbx), %rax
testq %rax, %rax
je 0xdbcf
xorl %r15d, %r15d
xorl %r14d, %r14d
movq 0x40(%rax), %rcx
movq 0x48(%rax), %rdx
movq 0x38(%rax), %rsi
cmpb $0x0, 0x38(%rcx)
cmoveq %rdx, %r14
cmovneq %rdx, %r15
movq %rsi, %rax
testq %rsi, %rsi
jne 0xd8f0
jmp 0xdbd5
movl 0x8409(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x8400(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, %r15
movl 0x83ed(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x83e4(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, -0x30(%rbp)
movq 0x40(%rbx), %rcx
movq 0x18(%rcx), %rdx
movl 0x30(%rax), %r8d
movl $0x13, %edi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xc0ff
movq %rax, %r14
movl 0x30(%r15), %esi
movl $0x10, %edi
callq 0xc0cb
movq %rax, -0x38(%rbp)
leaq 0x20(%rbx), %r12
movq %r12, %rdi
movq %r15, %rsi
callq 0xc40e
movq 0x40(%rbx), %rdx
addq $0x20, %rdx
movq %r12, %rdi
movq %r12, %rsi
callq 0xc383
movq %r12, %rdi
movq %r14, %rsi
callq 0xc40e
movq 0x48(%rbx), %rdi
movq %r12, %rsi
callq 0xd678
movq %r12, %rdi
movq -0x38(%rbp), %rsi
callq 0xc40e
movq %r12, %rdi
movq -0x30(%rbp), %rsi
jmp 0xd9eb
leaq 0x20(%rbx), %r14
movq 0x40(%rbx), %rax
movq 0x18(%rax), %rdx
movl $0xe, %edi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xc084
movq %r14, %rdi
movq %rax, %rsi
callq 0xc40e
movl (%r13), %eax
testl %eax, %eax
jle 0xda6b
movl (%rbx), %eax
cmpq $0x12, %rax
ja 0xda6b
leaq 0x252d(%rip), %rcx      # 0xff34
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x40(%rbx), %rdi
addq $0x20, %rdi
callq 0xc4eb
movq 0x48(%rbx), %rdi
jmp 0xda9d
movq 0x48(%rbx), %rax
testq %rax, %rax
je 0xda46
movq 0x40(%rax), %rdi
addq $0x20, %rdi
callq 0xc4eb
movq 0x48(%rbx), %rax
movq 0x48(%rax), %rdi
callq 0xd6ae
movq 0x50(%rbx), %rbx
testq %rbx, %rbx
je 0xda6b
movq 0x48(%rbx), %rdi
callq 0xd6ae
movq 0x40(%rbx), %rdi
addq $0x20, %rdi
callq 0xc4eb
movq 0x38(%rbx), %rbx
jmp 0xda4a
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x58(%rbx), %rdi
jmp 0xdac7
movq 0x38(%rbx), %rdi
jmp 0xda9d
movq 0x38(%rbx), %rdi
addq $0x20, %rdi
callq 0xc4eb
movq 0x40(%rbx), %rdi
jmp 0xda9d
movq 0x60(%rbx), %rdi
addq $0x20, %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xc4eb
movq 0x48(%rbx), %rdi
callq 0xd6ae
movq 0x50(%rbx), %rdi
jmp 0xdac7
movq 0x40(%rbx), %rdi
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xd6ae
movl 0x8244(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x823b(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, -0x30(%rbp)
movq 0x50(%rbx), %r14
testq %r14, %r14
je 0xdb9b
leaq 0x20(%rbx), %r15
movl 0x8216(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x820d(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, %r12
movq 0x18(%rbx), %rdx
movq 0x40(%r14), %rax
movq 0x18(%rax), %rcx
movl 0x30(%r12), %r8d
movl $0x12, %edi
xorl %esi, %esi
callq 0xc0ff
movq %r15, %rdi
movq %rax, %rsi
callq 0xc40e
movq 0x48(%r14), %rdi
movq %r15, %rsi
callq 0xd678
movq -0x30(%rbp), %rax
movl 0x30(%rax), %esi
movl $0x10, %edi
callq 0xc0cb
movq %r15, %rdi
movq %rax, %rsi
callq 0xc40e
movl 0x30(%r12), %esi
movl $0x15, %edi
callq 0xc0cb
movq %r15, %rdi
movq %rax, %rsi
callq 0xc40e
movq 0x38(%r14), %r14
testq %r14, %r14
jne 0xdb08
movq -0x30(%rbp), %r14
movq 0x48(%rbx), %rax
testq %rax, %rax
je 0xdbb5
movq 0x48(%rax), %rdi
leaq 0x20(%rbx), %rsi
callq 0xd678
leaq 0x20(%rbx), %r15
movl 0x30(%r14), %esi
movl $0x15, %edi
callq 0xc0cb
movq %r15, %rdi
jmp 0xd9e8
xorl %r14d, %r14d
xorl %r15d, %r15d
movl 0x8149(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x8140(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, -0x30(%rbp)
movl 0x812c(%rip), %esi      # 0x15d24
leal 0x1(%rsi), %eax
movl %eax, 0x8123(%rip)      # 0x15d24
movl $0x15, %edi
callq 0xc0cb
movq %rax, -0x38(%rbp)
leaq 0x20(%rbx), %r12
movq 0x18(%rbx), %rdx
movq -0x30(%rbp), %rax
movl 0x30(%rax), %r8d
movl $0x13, %edi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xc0ff
movq %r12, %rdi
movq %rax, %rsi
callq 0xc40e
movq %r15, %rdi
movq %r12, %rsi
callq 0xd678
movq -0x38(%rbp), %r15
movl 0x30(%r15), %esi
movl $0x10, %edi
callq 0xc0cb
movq %r12, %rdi
movq %rax, %rsi
callq 0xc40e
movq %r12, %rdi
movq -0x30(%rbp), %rsi
callq 0xc40e
movq %r14, %rdi
movq %r12, %rsi
callq 0xd678
movq %r12, %rdi
movq %r15, %rsi
jmp 0xd9eb