// File: /workspace/github_c_makefile_star2_O2/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
pushq %rax
movq %rdi, %rbx
leaq 0xd692(%rip), %r15      # 0x19db8
movl (%r15), %eax
testl %eax, %eax
jne 0xca0d
cmpb $0x1, 0x85e8(%rip)      # 0x14d20
jne 0xca87
movl (%rbx), %esi
cmpq $0x12, %rsi
ja 0xc87e
leaq 0x2797(%rip), %rax      # 0xeee8
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 0xb421
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 0xc9fa
leaq 0x20(%rbx), %r14
movq 0x18(%rbx), %rsi
pushq $0xf
popq %rdi
xorl %edx, %edx
jmp 0xc9f8
leaq 0x20(%rbx), %r14
movq 0x18(%rbx), %rsi
movq 0x50(%rbx), %rdx
pushq $0xc
popq %rdi
xorl %ecx, %ecx
callq 0xb180
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
movl 0x8559(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x8550(%rip)      # 0x14d24
pushq $0x15
popq %r13
movl %r13d, %edi
callq 0xb1c2
movq %rax, %r15
movl 0x853b(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x8532(%rip)      # 0x14d24
movl %r13d, %edi
callq 0xb1c2
movq %rax, %r12
movq 0x18(%rbx), %rdx
movq 0x58(%rbx), %rcx
movl 0x30(%rax), %r8d
pushq $0x11
popq %rdi
xorl %esi, %esi
callq 0xb1f1
movq %rax, %r13
movl 0x30(%r15), %esi
pushq $0x10
popq %rdi
callq 0xb1c2
movq %rax, -0x30(%rbp)
movq %r14, %rdi
movq %r15, %rsi
leaq 0xd585(%rip), %r15      # 0x19db8
callq 0xb4ac
movq %r14, %rdi
movq %r13, %rsi
callq 0xb4ac
movq 0x60(%rbx), %rdi
movq %r14, %rsi
callq 0xc6b0
movq 0x18(%rbx), %rsi
pushq $0x16
popq %rdi
xorl %edx, %edx
xorl %ecx, %ecx
callq 0xb180
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
movq %r14, %rdi
movq -0x30(%rbp), %rsi
callq 0xb4ac
movq %r14, %rdi
jmp 0xc9e2
leaq 0x25df(%rip), %rdi      # 0xee64
callq 0x6ec4
jmp 0xca0a
leaq 0x20(%rbx), %r14
movq 0x38(%rbx), %rsi
addq $0x20, %rsi
movq %r14, %rdi
callq 0xb407
movq 0x18(%rbx), %rsi
movq 0x38(%rbx), %rax
movq 0x18(%rax), %rdx
pushq $0xd
jmp 0xc8d9
leaq 0x20(%rbx), %r14
movq 0x48(%rbx), %rsi
addq $0x20, %rsi
movq %r14, %rdi
callq 0xb407
movq 0x40(%rbx), %rax
movq 0x48(%rbx), %rcx
movq 0x18(%rax), %rsi
movq 0x18(%rcx), %rdx
pushq $0xc
popq %rdi
jmp 0xc9f8
movq 0x58(%rbx), %rdi
leaq 0x20(%rbx), %rsi
callq 0xc6b0
jmp 0xca0a
movq 0x18(%rbx), %rax
cmpl $0x3, 0x18(%rax)
jne 0xcaf6
leaq 0x50(%rbx), %rax
xorl %r14d, %r14d
xorl %r15d, %r15d
movq (%rax), %rax
testq %rax, %rax
je 0xcbae
movq 0x40(%rax), %rcx
movq 0x48(%rax), %rdx
cmpb $0x0, 0x38(%rcx)
cmoveq %rdx, %r14
cmovneq %rdx, %r15
addq $0x38, %rax
jmp 0xc909
movl 0x83ef(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x83e6(%rip)      # 0x14d24
pushq $0x15
popq %r14
movl %r14d, %edi
callq 0xb1c2
movq %rax, %r15
movl 0x83d1(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x83c8(%rip)      # 0x14d24
movl %r14d, %edi
callq 0xb1c2
movq %rax, %r12
movq 0x40(%rbx), %rax
movq 0x18(%rax), %rdx
movl 0x30(%r12), %r8d
pushq $0x13
popq %rdi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xb1f1
movq %rax, %r14
movl 0x30(%r15), %esi
pushq $0x10
popq %rdi
callq 0xb1c2
movq %rax, -0x30(%rbp)
leaq 0x20(%rbx), %r13
movq %r13, %rdi
movq %r15, %rsi
leaq 0xd414(%rip), %r15      # 0x19db8
callq 0xb4ac
movq 0x40(%rbx), %rdx
addq $0x20, %rdx
movq %r13, %rdi
movq %r13, %rsi
callq 0xb421
movq %r13, %rdi
movq %r14, %rsi
callq 0xb4ac
movq 0x48(%rbx), %rdi
movq %r13, %rsi
callq 0xc6b0
movq %r13, %rdi
movq -0x30(%rbp), %rsi
callq 0xb4ac
movq %r13, %rdi
movq %r12, %rsi
jmp 0xca05
leaq 0x20(%rbx), %r14
movq 0x40(%rbx), %rax
movq 0x18(%rax), %rdx
pushq $0xe
popq %rdi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xb180
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
movl (%r15), %eax
testl %eax, %eax
jle 0xca87
movl (%rbx), %eax
cmpq $0x12, %rax
ja 0xca87
leaq 0x2514(%rip), %rcx      # 0xef34
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq 0x40(%rbx), %rdi
addq $0x20, %rdi
callq 0xb583
movq 0x48(%rbx), %rdi
jmp 0xcab9
movq 0x48(%rbx), %rax
testq %rax, %rax
je 0xca5f
movq 0x40(%rax), %rdi
addq $0x20, %rdi
callq 0xb583
movq 0x48(%rbx), %rax
movq 0x48(%rax), %rdi
callq 0xc6e3
addq $0x50, %rbx
movq (%rbx), %rbx
testq %rbx, %rbx
je 0xca87
movq 0x48(%rbx), %rdi
callq 0xc6e3
movq 0x40(%rbx), %rdi
addq $0x20, %rdi
callq 0xb583
addq $0x38, %rbx
jmp 0xca63
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x58(%rbx), %rdi
jmp 0xcae3
movq 0x38(%rbx), %rdi
jmp 0xcab9
movq 0x38(%rbx), %rdi
addq $0x20, %rdi
callq 0xb583
movq 0x40(%rbx), %rdi
jmp 0xcab9
movq 0x60(%rbx), %rdi
addq $0x20, %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xb583
movq 0x48(%rbx), %rdi
callq 0xc6e3
movq 0x50(%rbx), %rdi
jmp 0xcae3
movq 0x40(%rbx), %rdi
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0xc6e3
movl 0x8228(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x821f(%rip)      # 0x14d24
pushq $0x15
popq %rdi
callq 0xb1c2
movq %rax, -0x30(%rbp)
leaq 0x50(%rbx), %r15
leaq 0x20(%rbx), %r14
pushq $0x15
popq %r12
movq (%r15), %r15
testq %r15, %r15
je 0xcc4f
movl 0x81f5(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x81ec(%rip)      # 0x14d24
movl %r12d, %edi
callq 0xb1c2
movq %rax, %r13
movq 0x18(%rbx), %rdx
movq 0x40(%r15), %rax
movq 0x18(%rax), %rcx
movl 0x30(%r13), %r8d
pushq $0x12
popq %rdi
xorl %esi, %esi
callq 0xb1f1
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
movq 0x48(%r15), %rdi
movq %r14, %rsi
callq 0xc6b0
movq -0x30(%rbp), %rax
movl 0x30(%rax), %esi
pushq $0x10
popq %rdi
callq 0xb1c2
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
movl 0x30(%r13), %esi
movl %r12d, %edi
callq 0xb1c2
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
addq $0x38, %r15
jmp 0xcb1d
movl 0x8170(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x8167(%rip)      # 0x14d24
pushq $0x15
popq %r13
movl %r13d, %edi
callq 0xb1c2
movq %rax, %r12
movl 0x8152(%rip), %esi      # 0x14d24
leal 0x1(%rsi), %eax
movl %eax, 0x8149(%rip)      # 0x14d24
movl %r13d, %edi
callq 0xb1c2
movq %rax, -0x30(%rbp)
leaq 0x20(%rbx), %r13
movq 0x18(%rbx), %rdx
movl 0x30(%r12), %r8d
pushq $0x13
popq %rdi
xorl %esi, %esi
xorl %ecx, %ecx
callq 0xb1f1
movq %r13, %rdi
movq %rax, %rsi
callq 0xb4ac
movq %r15, %rdi
movq %r13, %rsi
callq 0xc6b0
movq -0x30(%rbp), %r15
movl 0x30(%r15), %esi
pushq $0x10
popq %rdi
callq 0xb1c2
movq %r13, %rdi
movq %rax, %rsi
callq 0xb4ac
movq %r13, %rdi
movq %r12, %rsi
callq 0xb4ac
movq %r14, %rdi
movq %r13, %rsi
callq 0xc6b0
movq %r13, %rdi
movq %r15, %rsi
jmp 0xcc79
movq 0x48(%rbx), %rax
testq %rax, %rax
je 0xcc64
movq 0x48(%rax), %rdi
movq %r14, %rsi
callq 0xc6b0
movq -0x30(%rbp), %rax
movl 0x30(%rax), %esi
pushq $0x15
popq %rdi
callq 0xb1c2
movq %r14, %rdi
movq %rax, %rsi
callq 0xb4ac
leaq 0xd133(%rip), %r15      # 0x19db8
jmp 0xca0a