// File: cphinton42[P]hinton-language/src/check.cpp
// Function: combine_number_types(Context*, Expr_AST*, Expr_AST*, Primitive_AST**)
internal
Status combine_number_types(Context *ctx, Expr_AST *t1, Expr_AST *t2, Primitive_AST **out)
{
    Expr_AST *reduced_t1, *reduced_t2;
    Status status = reduce_type(ctx, t1, &reduced_t1);
    if(status != Status::good)
    {
        return status;
    }
    status = reduce_type(ctx, t2, &reduced_t2);
    if(status != Status::good)
    {
        return status;
    }
    if(reduced_t1->type != AST_Type::primitive_ast)
    {
        report_error("Expected number type", t1);
        ctx->success = false;
        return Status::bad;
    }
    if(reduced_t2->type != AST_Type::primitive_ast)
    {
        report_error("Expected number type", t2);
        ctx->success = false;
        return Status::bad;
    }
    Primitive_AST *prim_ast1 = static_cast<Primitive_AST*>(reduced_t1);
    Primitive_AST *prim_ast2 = static_cast<Primitive_AST*>(reduced_t2);
    
    u64 prim1 = prim_ast1->primitive;
    u64 prim2 = prim_ast2->primitive;
    u64 size1 = prim1 & PRIM_SIZE_MASK;
    u64 size2 = prim2 & PRIM_SIZE_MASK;
    u64 max_size = max(size1, size2);
    
    if((prim1 & PRIM_FLOATLIKE) && (prim2 & PRIM_FLOATLIKE))
    {
        if(max_size == PRIM_NO_SIZE)
        {
            // TODO: should this be a concrete type, rather than floatlike?
            *out = &floatlike_t_ast;
        }
        else if(max_size == PRIM_SIZE4)
        {
            *out = &f32_t_ast;
        }
        else
        {
            assert(max_size == PRIM_SIZE8);
            *out = &f64_t_ast;
        }
    }
    else if((prim1 & PRIM_INTLIKE) && (prim2 & PRIM_INTLIKE))
    {
        // TODO: maybe a warning or error if mixing signed and unsigned?
        // Maybe only if u64 and s64, since u64 doesn't necessarily fit in s64
        if((prim1 & PRIM_SIGN_MASK) == PRIM_UNSIGNED_INT && (prim2 & PRIM_SIGN_MASK) == PRIM_UNSIGNED_INT)
        {
            switch(max_size)
            {
                case PRIM_NO_SIZE: {
                    // TODO: maybe make uintlike_t_ast ?
                    *out = &intlike_t_ast;
                } break;
                case PRIM_SIZE1: {
                    *out = &u8_t_ast;
                } break;
                case PRIM_SIZE2: {
                    *out = &u16_t_ast;
                } break;
                case PRIM_SIZE4: {
                    *out = &u32_t_ast;
                } break;
                case PRIM_SIZE8: {
                    *out = &u64_t_ast;
                } break;
                default: {
                    assert(false);
                } break;
            }
        }
        else
        {
            switch(max_size)
            {
                case PRIM_NO_SIZE: {
                    *out = &intlike_t_ast;
                } break;
                case PRIM_SIZE1: {
                    *out = &s8_t_ast;
                } break;
                case PRIM_SIZE2: {
                    *out = &s16_t_ast;
                } break;
                case PRIM_SIZE4: {
                    *out = &s32_t_ast;
                } break;
                case PRIM_SIZE8: {
                    *out = &s64_t_ast;
                } break;
                default: {
                    assert(false);
                } break;
            }
        }
    }
    else
    {
        // TODO: better error reporting
        report_error("Number types don't match", t1, t2);
        ctx->success = false;
        return Status::bad;
    }
    
    return Status::good;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x90, %rsp
movq %rdi, -0x10(%rbp)
movq %rsi, -0x18(%rbp)
movq %rdx, -0x20(%rbp)
movq %rcx, -0x28(%rbp)
movq -0x10(%rbp), %rdi
movq -0x18(%rbp), %rsi
leaq -0x30(%rbp), %rdx
callq 0x9040
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
je 0x12050
movl -0x3c(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x12350
movq -0x10(%rbp), %rdi
movq -0x20(%rbp), %rsi
leaq -0x38(%rbp), %rdx
callq 0x9040
movl %eax, -0x3c(%rbp)
cmpl $0x0, -0x3c(%rbp)
je 0x12075
movl -0x3c(%rbp), %eax
movl %eax, -0x4(%rbp)
jmp 0x12350
movq -0x30(%rbp), %rax
cmpw $0x11, (%rax)
je 0x120a3
movq -0x18(%rbp), %rsi
leaq 0x8a62(%rip), %rdi      # 0x1aaec
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
movl $0x2, -0x4(%rbp)
jmp 0x12350
movq -0x38(%rbp), %rax
cmpw $0x11, (%rax)
je 0x120d1
movq -0x20(%rbp), %rsi
leaq 0x8a34(%rip), %rdi      # 0x1aaec
callq 0x4950
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
movl $0x2, -0x4(%rbp)
jmp 0x12350
movq -0x30(%rbp), %rax
movq %rax, -0x48(%rbp)
movq -0x38(%rbp), %rax
movq %rax, -0x50(%rbp)
movq -0x48(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x58(%rbp)
movq -0x50(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x60(%rbp)
movq -0x58(%rbp), %rax
andq $0x7, %rax
movq %rax, -0x68(%rbp)
movq -0x60(%rbp), %rax
andq $0x7, %rax
movq %rax, -0x70(%rbp)
movq -0x68(%rbp), %rdi
movq -0x70(%rbp), %rsi
callq 0x17ed0
movq %rax, -0x78(%rbp)
movq -0x58(%rbp), %rax
andq $0x40, %rax
cmpq $0x0, %rax
je 0x121a9
movq -0x60(%rbp), %rax
andq $0x40, %rax
cmpq $0x0, %rax
je 0x121a9
cmpq $0x0, -0x78(%rbp)
jne 0x12155
movq -0x28(%rbp), %rax
leaq 0xddf0(%rip), %rcx      # 0x1ff40
movq %rcx, (%rax)
jmp 0x121a4
cmpq $0x3, -0x78(%rbp)
jne 0x1216c
movq -0x28(%rbp), %rax
leaq 0xdd11(%rip), %rcx      # 0x1fe78
movq %rcx, (%rax)
jmp 0x121a2
cmpq $0x4, -0x78(%rbp)
jne 0x12175
jmp 0x12194
leaq 0x8985(%rip), %rdi      # 0x1ab01
leaq 0x7d69(%rip), %rsi      # 0x19eec
movl $0x6ca, %edx            # imm = 0x6CA
leaq 0x8989(%rip), %rcx      # 0x1ab18
callq 0x3080
movq -0x28(%rbp), %rax
leaq 0xdd01(%rip), %rcx      # 0x1fea0
movq %rcx, (%rax)
jmp 0x121a4
jmp 0x12349
movq -0x58(%rbp), %rax
andq $0x20, %rax
cmpq $0x0, %rax
je 0x12322
movq -0x60(%rbp), %rax
andq $0x20, %rax
cmpq $0x0, %rax
je 0x12322
movq -0x58(%rbp), %rax
andq $0x18, %rax
cmpq $0x10, %rax
jne 0x12287
movq -0x60(%rbp), %rax
andq $0x18, %rax
cmpq $0x10, %rax
jne 0x12287
movq -0x78(%rbp), %rax
movq %rax, -0x80(%rbp)
subq $0x4, %rax
ja 0x12263
movq -0x80(%rbp), %rax
leaq 0x753a(%rip), %rcx      # 0x19744
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x28(%rbp), %rax
leaq 0xdcfa(%rip), %rcx      # 0x1ff18
movq %rcx, (%rax)
jmp 0x12282
movq -0x28(%rbp), %rax
leaq 0xda6a(%rip), %rcx      # 0x1fc98
movq %rcx, (%rax)
jmp 0x12282
movq -0x28(%rbp), %rax
leaq 0xda82(%rip), %rcx      # 0x1fcc0
movq %rcx, (%rax)
jmp 0x12282
movq -0x28(%rbp), %rax
leaq 0xda9a(%rip), %rcx      # 0x1fce8
movq %rcx, (%rax)
jmp 0x12282
movq -0x28(%rbp), %rax
leaq 0xdab2(%rip), %rcx      # 0x1fd10
movq %rcx, (%rax)
jmp 0x12282
leaq 0x7bb8(%rip), %rdi      # 0x19e22
leaq 0x7c7b(%rip), %rsi      # 0x19eec
movl $0x6e7, %edx            # imm = 0x6E7
leaq 0x889b(%rip), %rcx      # 0x1ab18
callq 0x3080
jmp 0x12320
movq -0x78(%rbp), %rax
movq %rax, -0x88(%rbp)
subq $0x4, %rax
ja 0x122ff
movq -0x88(%rbp), %rax
leaq 0x748a(%rip), %rcx      # 0x19730
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x28(%rbp), %rax
leaq 0xdc5e(%rip), %rcx      # 0x1ff18
movq %rcx, (%rax)
jmp 0x1231e
movq -0x28(%rbp), %rax
leaq 0xda6e(%rip), %rcx      # 0x1fd38
movq %rcx, (%rax)
jmp 0x1231e
movq -0x28(%rbp), %rax
leaq 0xda86(%rip), %rcx      # 0x1fd60
movq %rcx, (%rax)
jmp 0x1231e
movq -0x28(%rbp), %rax
leaq 0xda9e(%rip), %rcx      # 0x1fd88
movq %rcx, (%rax)
jmp 0x1231e
movq -0x28(%rbp), %rax
leaq 0xdab6(%rip), %rcx      # 0x1fdb0
movq %rcx, (%rax)
jmp 0x1231e
leaq 0x7b1c(%rip), %rdi      # 0x19e22
leaq 0x7bdf(%rip), %rsi      # 0x19eec
movl $0x6ff, %edx            # imm = 0x6FF
leaq 0x87ff(%rip), %rcx      # 0x1ab18
callq 0x3080
jmp 0x12320
jmp 0x12347
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
leaq 0x8838(%rip), %rdi      # 0x1ab69
callq 0x4a30
movq -0x10(%rbp), %rax
movb $0x0, 0x10(%rax)
movl $0x2, -0x4(%rbp)
jmp 0x12350
jmp 0x12349
movl $0x0, -0x4(%rbp)
movl -0x4(%rbp), %eax
addq $0x90, %rsp
popq %rbp
retq
nopl (%rax)