// File: /workspace/github_c_makefile_star2_O3/yutopp[P]cc/ir.c
// Function: build_expression
IRSymbolID build_expression(IRBuilder* builder, Node* node, IRFunction* f) {
    switch(node->kind) {
    case NODE_EXPR_BIN:
    {
        printf("LOG: expr bin = ");
        token_fprint_buf(stdout, node->value.expr_bin.op);
        printf("\n");

        IRSymbolID lhs_sym = build_expression(builder, node->value.expr_bin.lhs, f);
        IRSymbolID rhs_sym = build_expression(builder, node->value.expr_bin.rhs, f);

        IRSymbolID sym_id = ir_builder_build_local(builder);

        IRInstValue bin = {
            .kind = IR_INST_VALUE_KIND_OP_BIN,
            .value = {
                .op_bin = {
                    .op = node->value.expr_bin.op, // TODO: Change to builtin enums...
                    .lhs = lhs_sym,
                    .rhs = rhs_sym,
                },
            },
        };
        IRInst inst = {
            .kind = IR_INST_KIND_LET,
            .value = {
                .let = {
                    .id = sym_id,
                    .rhs = bin,
                },
            },
        };
        ir_bb_append_inst(builder->current_bb, &inst);
        ir_function_set_local(f, sym_id, 8); // TODO: fix

        return sym_id;
    }

    case NODE_EXPR_POSTFIX:
    {
        printf("LOG: expr post = \n");

        IRSymbolID lhs_sym = build_expression(builder, node->value.expr_postfix.lhs, f);

        switch(node->value.expr_postfix.kind) {
        case NODE_EXPR_POSTFIX_KIND_FUNC_CALL:
        {
            Vector* args = vector_new(sizeof(IRSymbolID)); // Vector<IRSymbolID>
            Node* args_list = node->value.expr_postfix.rhs;
            if (args_list) {
                assert(args_list->kind == NODE_ARGS_LIST);
                for(size_t i=0; i<vector_len(args_list->value.args_list.args); ++i) {
                    Node** a = (Node**)vector_at(args_list->value.args_list.args, i);
                    IRSymbolID a_sym = build_expression(builder, *a, f);

                    IRSymbolID* args_e = (IRSymbolID*)vector_append(args);
                    *args_e = a_sym;
                }
            }

            IRSymbolID sym_id = ir_builder_build_local(builder);

            IRInstValue call = {
                .kind = IR_INST_VALUE_KIND_CALL,
                .value = {
                    .call = {
                        .lhs = lhs_sym,
                        .args = args,
                    },
                },
            };
            IRInst inst = {
                .kind = IR_INST_KIND_LET,
                .value = {
                    .let = {
                        .id = sym_id,
                        .rhs = call,
                    },
                },
            };
            ir_bb_append_inst(builder->current_bb, &inst);
            ir_function_set_local(f, sym_id, 8); // TODO: fix

            return sym_id;
        }

        default:
            assert(0); // TODO: error handling...
        }
        break;
    }

    case NODE_LIT_INT:
    {
        printf("LOG: lit_int\n");
        IRSymbolID sym_id = ir_builder_build_local(builder);

        IRInstValue imm = {
            .kind = IR_INST_VALUE_KIND_IMM_INT,
            .value = {
                .imm_int = node->value.lit_int.v,
            },
        };
        IRInst inst = {
            .kind = IR_INST_KIND_LET,
            .value = {
                .let = {
                    .id = sym_id,
                    .rhs = imm,
                },
            },
        };
        ir_bb_append_inst(builder->current_bb, &inst);
        ir_function_set_local(f, sym_id, 8); // TODO: fix

        return sym_id;
    }

    case NODE_LIT_STRING:
    {
        printf("LOG: lit_string\n");

        IRInstValue sval = {
            .kind = IR_INST_VALUE_KIND_STRING,
            .value = {
                .string = node->value.lit_string.v,
            },
        };
        IRSymbolID str_sym_id = insert_definition(f->mod, sval);

        //
        IRSymbolID ref_sym_id = ir_builder_build_local(builder);

        {
            IRInstValue ref = {
                .kind = IR_INST_VALUE_KIND_REF,
                .value = {
                    .ref = {
                        .is_global = 1,
                        .sym = str_sym_id,
                    },
                },
            };
            IRInst inst = {
                .kind = IR_INST_KIND_LET,
                .value = {
                    .let = {
                        .id = ref_sym_id,
                        .rhs = ref,
                    },
                },
            };
            ir_bb_append_inst(builder->current_bb, &inst);
            ir_function_set_local(f, ref_sym_id, 8); // TODO: fix
        }

        IRSymbolID sym_id = ir_builder_build_local(builder);

        IRInstValue addr_of = {
            .kind = IR_INST_VALUE_KIND_ADDR_OF,
            .value = {
                .addr_of = {
                    .sym = ref_sym_id,
                },
            },
        };
        IRInst inst = {
            .kind = IR_INST_KIND_LET,
            .value = {
                .let = {
                    .id = sym_id,
                    .rhs = addr_of,
                },
            },
        };
        ir_bb_append_inst(builder->current_bb, &inst);
        ir_function_set_local(f, sym_id, 8); // TODO: fix

        return sym_id;
    }

    case NODE_ID:
    {
        // TODO: implement
        IRInstValue val = {
            .kind = IR_INST_VALUE_KIND_SYMBOL,
            .value = {
                .symbol = token_to_string(node->value.id.tok),
            },
        };
        IRSymbolID tmp_sym_id = insert_definition(f->mod, val);

        IRSymbolID sym_id = ir_builder_build_local(builder);

        IRInstValue ref = {
            .kind = IR_INST_VALUE_KIND_REF,
            .value = {
                .ref = {
                    .is_global = 1,
                    .sym = tmp_sym_id,
                },
            },
        };
        IRInst inst = {
            .kind = IR_INST_KIND_LET,
            .value = {
                .let = {
                    .id = sym_id,
                    .rhs = ref,
                },
            },
        };
        ir_bb_append_inst(builder->current_bb, &inst);
        ir_function_set_local(f, sym_id, 8); // TODO: fix

        return sym_id;
    }

    default:
        assert(0); // TODO: error handling...
    }
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
pushq %rax
movl (%rsi), %eax
addl $-0x6, %eax
cmpl $0x4, %eax
ja 0x42a3
movq %rdx, %rbx
movq %rsi, %r12
movq %rdi, %r14
leaq 0x353a(%rip), %rcx      # 0x74bc
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
leaq 0x36fe(%rip), %rdi      # 0x7690
xorl %eax, %eax
callq 0x10b0
movq 0x7038(%rip), %rax      # 0xafd8
movq (%rax), %rdi
movq 0x8(%r12), %rsi
callq 0x1c61
movl $0xa, %edi
callq 0x1050
movq 0x10(%r12), %rsi
movq %r14, %rdi
movq %rbx, %rdx
callq 0x3f59
movq %rax, %r13
movq 0x18(%r12), %rsi
movq %r14, %rdi
movq %rbx, %rdx
callq 0x3f59
movq %rax, %rbp
movq (%r14), %rax
movq 0x30(%rax), %r15
leaq 0x1(%r15), %rcx
movq %rcx, 0x30(%rax)
movq 0x8(%r12), %r12
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
movl $0x0, (%rax)
movq %r15, 0x8(%rax)
movl $0x5, 0x10(%rax)
movq %r12, 0x18(%rax)
movq %r13, 0x20(%rax)
movq %rbp, 0x28(%rax)
jmp 0x4262
movq 0x8(%r12), %rdi
callq 0x1b54
movq %rax, %r15
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq 0x10(%rax), %r12
leaq 0x1(%r12), %rcx
movq %rcx, 0x10(%rax)
callq 0x2eb0
xorl %ebp, %ebp
movl %ebp, (%rax)
movq %r12, 0x8(%rax)
movl %ebp, 0x10(%rax)
movq %r15, 0x18(%rax)
movq (%r14), %rax
movq 0x30(%rax), %r15
leaq 0x1(%r15), %rcx
movq %rcx, 0x30(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
movl %ebp, (%rax)
movq %r15, 0x8(%rax)
movl $0x2, 0x10(%rax)
movl $0x1, 0x18(%rax)
movq %r12, 0x20(%rax)
jmp 0x4262
leaq 0x371a(%rip), %rdi      # 0x77af
callq 0x1070
movq (%r14), %rax
movq 0x30(%rax), %r15
leaq 0x1(%r15), %rcx
movq %rcx, 0x30(%rax)
movl 0x8(%r12), %ebp
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
xorl %ecx, %ecx
movl %ecx, (%rax)
movq %r15, 0x8(%rax)
movq $0x4, 0x10(%rax)
movl %ebp, 0x18(%rax)
xorps %xmm0, %xmm0
movups %xmm0, 0x1c(%rax)
movl %ecx, 0x2c(%rax)
jmp 0x4262
leaq 0x36bb(%rip), %rdi      # 0x779f
callq 0x1070
movq 0x8(%r12), %r15
movq 0x8(%rbx), %rax
movq (%rax), %rdi
movq 0x10(%rax), %r13
leaq 0x1(%r13), %rcx
movq %rcx, 0x10(%rax)
callq 0x2eb0
xorl %ecx, %ecx
movl %ecx, (%rax)
movq %r13, 0x8(%rax)
movl $0x1, %ebp
movl %ebp, 0x10(%rax)
movq %r15, 0x18(%rax)
movq (%r14), %rax
movq 0x30(%rax), %r12
leaq 0x1(%r12), %rcx
movq %rcx, 0x30(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
xorl %ecx, %ecx
movl %ecx, (%rax)
movq %r12, 0x8(%rax)
movl $0x2, 0x10(%rax)
movl %ebp, 0x18(%rax)
movq %r13, 0x20(%rax)
movl $0x8, %edx
movq %rbx, %rdi
movq %r12, %rsi
callq 0x3550
movq (%r14), %rax
movq 0x30(%rax), %r15
leaq 0x1(%r15), %rcx
movq %rcx, 0x30(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
xorl %ecx, %ecx
movl %ecx, (%rax)
movq %r15, 0x8(%rax)
movl $0x3, 0x10(%rax)
movq %r12, 0x18(%rax)
jmp 0x4262
leaq 0x3624(%rip), %rdi      # 0x77bc
callq 0x1070
movq 0x10(%r12), %rsi
movq %r14, %rdi
movq %rbx, %rdx
callq 0x3f59
cmpl $0x0, 0x8(%r12)
jne 0x4284
movq %rax, (%rsp)
movl $0x8, %edi
callq 0x2d9c
movq %rax, %rbp
movq 0x18(%r12), %r13
testq %r13, %r13
je 0x4229
cmpl $0xb, (%r13)
jne 0x42c2
movq 0x8(%r13), %rdi
callq 0x2f0b
testq %rax, %rax
je 0x4229
xorl %r15d, %r15d
movq 0x8(%r13), %rdi
movq %r15, %rsi
callq 0x2ef6
movq (%rax), %rsi
movq %r14, %rdi
movq %rbx, %rdx
callq 0x3f59
movq %rax, %r12
movq %rbp, %rdi
callq 0x2eb0
movq %r12, (%rax)
incq %r15
movq 0x8(%r13), %rdi
callq 0x2f0b
cmpq %rax, %r15
jb 0x41f0
movq (%r14), %rax
movq 0x30(%rax), %r15
leaq 0x1(%r15), %rcx
movq %rcx, 0x30(%rax)
movq 0x8(%r14), %rax
movq 0x10(%rax), %rdi
callq 0x2eb0
movl $0x0, (%rax)
movq %r15, 0x8(%rax)
movl $0x6, 0x10(%rax)
movq (%rsp), %rcx
movq %rcx, 0x18(%rax)
movq %rbp, 0x20(%rax)
movl $0x8, %edx
movq %rbx, %rdi
movq %r15, %rsi
callq 0x3550
movq %r15, %rax
addq $0x8, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
leaq 0x35b3(%rip), %rdi      # 0x783e
leaq 0x323e(%rip), %rsi      # 0x74d0
leaq 0x342a(%rip), %rcx      # 0x76c3
movl $0x1a1, %edx            # imm = 0x1A1
callq 0x10d0
leaq 0x3594(%rip), %rdi      # 0x783e
leaq 0x321f(%rip), %rsi      # 0x74d0
leaq 0x340b(%rip), %rcx      # 0x76c3
movl $0x225, %edx            # imm = 0x225
callq 0x10d0
leaq 0x33d8(%rip), %rdi      # 0x76a1
leaq 0x3200(%rip), %rsi      # 0x74d0
leaq 0x33ec(%rip), %rcx      # 0x76c3
movl $0x17c, %edx            # imm = 0x17C
callq 0x10d0
nopl (%rax)