// File: /workspace/github_c_makefile_star2_O2/vtereshkov[P]umka-lang/src/umka_const.c
// Function: constBinary
void constBinary(const Consts *consts, Const *lhs, const Const *rhs, TokenKind op, const Type *type)
{
    if (type->kind == TYPE_PTR)
    {
        switch (op)
        {
            case TOK_EQEQ:      lhs->intVal = lhs->ptrVal == rhs->ptrVal; break;
            case TOK_NOTEQ:     lhs->intVal = lhs->ptrVal != rhs->ptrVal; break;
            case TOK_GREATER:   lhs->intVal = lhs->ptrVal >  rhs->ptrVal; break;
            case TOK_LESS:      lhs->intVal = lhs->ptrVal <  rhs->ptrVal; break;
            case TOK_GREATEREQ: lhs->intVal = lhs->ptrVal >= rhs->ptrVal; break;
            case TOK_LESSEQ:    lhs->intVal = lhs->ptrVal <= rhs->ptrVal; break;             

            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }
    }
    else if (type->kind == TYPE_WEAKPTR)
    {
        switch (op)
        {
            case TOK_EQEQ:      lhs->intVal = lhs->weakPtrVal == rhs->weakPtrVal; break;
            case TOK_NOTEQ:     lhs->intVal = lhs->weakPtrVal != rhs->weakPtrVal; break;
            case TOK_GREATER:   lhs->intVal = lhs->weakPtrVal >  rhs->weakPtrVal; break;
            case TOK_LESS:      lhs->intVal = lhs->weakPtrVal <  rhs->weakPtrVal; break;
            case TOK_GREATEREQ: lhs->intVal = lhs->weakPtrVal >= rhs->weakPtrVal; break;
            case TOK_LESSEQ:    lhs->intVal = lhs->weakPtrVal <= rhs->weakPtrVal; break;             
            
            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }        
    }    
    else if (type->kind == TYPE_STR)
    {
        switch (op)
        {
            case TOK_PLUS:      strcat((char *)lhs->ptrVal, (char *)rhs->ptrVal); break;

            case TOK_EQEQ:      lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) == 0; break;
            case TOK_NOTEQ:     lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) != 0; break;
            case TOK_GREATER:   lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) >  0; break;
            case TOK_LESS:      lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) <  0; break;
            case TOK_GREATEREQ: lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) >= 0; break;
            case TOK_LESSEQ:    lhs->intVal = strcmp((char *)lhs->ptrVal, (char *)rhs->ptrVal) <= 0; break;

            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }        
    }
    else if (type->kind == TYPE_ARRAY || type->kind == TYPE_STRUCT)
    {
        switch (op)
        {
            case TOK_EQEQ:      lhs->intVal = constCompare(consts, lhs, rhs, type) == 0; break;
            case TOK_NOTEQ:     lhs->intVal = constCompare(consts, lhs, rhs, type) != 0; break;
            case TOK_GREATER:   lhs->intVal = constCompare(consts, lhs, rhs, type)  > 0; break;
            case TOK_LESS:      lhs->intVal = constCompare(consts, lhs, rhs, type)  < 0; break;
            case TOK_GREATEREQ: lhs->intVal = constCompare(consts, lhs, rhs, type) >= 0; break;
            case TOK_LESSEQ:    lhs->intVal = constCompare(consts, lhs, rhs, type) <= 0; break;            
            
            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }
    }    
    else if (typeReal(type))
    {
        switch (op)
        {
            case TOK_PLUS:  lhs->realVal += rhs->realVal; break;
            case TOK_MINUS: lhs->realVal -= rhs->realVal; break;
            case TOK_MUL:   lhs->realVal *= rhs->realVal; break;
            case TOK_DIV:
            {
                if (rhs->realVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                lhs->realVal /= rhs->realVal;
                break;
            }
            case TOK_MOD:
            {
                if (rhs->realVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                lhs->realVal = fmod(lhs->realVal, rhs->realVal);
                break;
            }

            case TOK_EQEQ:      lhs->intVal = lhs->realVal == rhs->realVal; break;
            case TOK_NOTEQ:     lhs->intVal = lhs->realVal != rhs->realVal; break;
            case TOK_GREATER:   lhs->intVal = lhs->realVal >  rhs->realVal; break;
            case TOK_LESS:      lhs->intVal = lhs->realVal <  rhs->realVal; break;
            case TOK_GREATEREQ: lhs->intVal = lhs->realVal >= rhs->realVal; break;
            case TOK_LESSEQ:    lhs->intVal = lhs->realVal <= rhs->realVal; break;

            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }       
    }
    else if (type->kind == TYPE_UINT)
    {
        switch (op)
        {
            case TOK_PLUS:  lhs->uintVal += rhs->uintVal; break;
            case TOK_MINUS: lhs->uintVal -= rhs->uintVal; break;
            case TOK_MUL:   lhs->uintVal *= rhs->uintVal; break;
            case TOK_DIV:
            {
                if (rhs->uintVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                lhs->uintVal /= rhs->uintVal;
                break;
            }
            case TOK_MOD:
            {
                if (rhs->uintVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                lhs->uintVal %= rhs->uintVal;
                break;
            }

            case TOK_SHL:   lhs->uintVal <<= rhs->uintVal; break;
            case TOK_SHR:   lhs->uintVal >>= rhs->uintVal; break;
            case TOK_AND:   lhs->uintVal &= rhs->uintVal; break;
            case TOK_OR:    lhs->uintVal |= rhs->uintVal; break;
            case TOK_XOR:   lhs->uintVal ^= rhs->uintVal; break;

            case TOK_EQEQ:      lhs->intVal = lhs->uintVal == rhs->uintVal; break;
            case TOK_NOTEQ:     lhs->intVal = lhs->uintVal != rhs->uintVal; break;
            case TOK_GREATER:   lhs->intVal = lhs->uintVal >  rhs->uintVal; break;
            case TOK_LESS:      lhs->intVal = lhs->uintVal <  rhs->uintVal; break;
            case TOK_GREATEREQ: lhs->intVal = lhs->uintVal >= rhs->uintVal; break;
            case TOK_LESSEQ:    lhs->intVal = lhs->uintVal <= rhs->uintVal; break;

            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }
    }
    else  // All ordinal types except TYPE_UINT
    {
        switch (op)
        {
            case TOK_PLUS:  lhs->intVal += rhs->intVal; break;
            case TOK_MINUS: lhs->intVal -= rhs->intVal; break;
            case TOK_MUL:   lhs->intVal *= rhs->intVal; break;
            case TOK_DIV:
            {
                if (rhs->intVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                if (lhs->intVal == LLONG_MIN && rhs->intVal == -1)
                    consts->error->handler(consts->error->context, "Overflow of int");
                lhs->intVal /= rhs->intVal;
                break;
            }
            case TOK_MOD:
            {
                if (rhs->intVal == 0)
                    consts->error->handler(consts->error->context, "Division by zero");
                if (lhs->intVal == LLONG_MIN && rhs->intVal == -1)
                    consts->error->handler(consts->error->context, "Overflow of int");
                lhs->intVal %= rhs->intVal;
                break;
            }

            case TOK_SHL:   lhs->intVal <<= rhs->intVal; break;
            case TOK_SHR:   lhs->intVal >>= rhs->intVal; break;
            case TOK_AND:   lhs->intVal &= rhs->intVal; break;
            case TOK_OR:    lhs->intVal |= rhs->intVal; break;
            case TOK_XOR:   lhs->intVal ^= rhs->intVal; break;

            case TOK_EQEQ:      lhs->intVal = lhs->intVal == rhs->intVal; break;
            case TOK_NOTEQ:     lhs->intVal = lhs->intVal != rhs->intVal; break;
            case TOK_GREATER:   lhs->intVal = lhs->intVal >  rhs->intVal; break;
            case TOK_LESS:      lhs->intVal = lhs->intVal <  rhs->intVal; break;
            case TOK_GREATEREQ: lhs->intVal = lhs->intVal >= rhs->intVal; break;
            case TOK_LESSEQ:    lhs->intVal = lhs->intVal <= rhs->intVal; break;

            default:            consts->error->handler(consts->error->context, "Illegal operator"); return;
        }
    }
}

// Assembly:
pushq %r15
pushq %r14
pushq %rbx
movq %rdx, %r14
movq %rsi, %rbx
movq %rdi, %r15
movl (%r8), %eax
leal -0x10(%rax), %edx
cmpl $0x6, %edx
ja 0x6455
leaq 0x638e7(%rip), %rsi     # 0x69cfc
movslq (%rsi,%rdx,4), %rdx
addq %rsi, %rdx
jmpq *%rdx
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0x667e
leaq 0x638e7(%rip), %rax     # 0x69d18
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
xorl %ecx, %ecx
testq %rax, %rax
jmp 0x64fb
movl %eax, %edx
andl $-0x2, %edx
cmpl $0xe, %edx
jne 0x6503
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0x6643
leaq 0x63a4e(%rip), %rcx     # 0x69ec4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movsd (%r14), %xmm0
cmpeqsd (%rbx), %xmm0
jmp 0x6739
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0x667e
leaq 0x638e3(%rip), %rax     # 0x69d84
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0x6669
leaq 0x6387f(%rip), %rcx     # 0x69d3c
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
jmp 0x64fb
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0x667e
leaq 0x63876(%rip), %rax     # 0x69d60
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
sete %cl
jmp 0x66f9
addl $-0x16, %ecx
cmpl $0xb, %eax
jne 0x6616
cmpl $0x20, %ecx
ja 0x667e
leaq 0x6390d(%rip), %rax     # 0x69e2c
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%r14), %rcx
testq %rcx, %rcx
jne 0x6545
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63b0d(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
xorl %edx, %edx
divq %rcx
jmp 0x65d8
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
seta %cl
jmp 0x66f9
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setae %cl
jmp 0x66f9
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setb %cl
jmp 0x66f9
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setbe %cl
jmp 0x66f9
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
xorl %ecx, %ecx
testq %rax, %rax
jmp 0x66a7
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
notq %rax
jmp 0x65d4
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
shrq $0x3f, %rax
movq %rax, (%rbx)
jmp 0x66fc
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
xorl %ecx, %ecx
testq %rax, %rax
jmp 0x66cf
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0x6962
xorl %ecx, %ecx
testq %rax, %rax
jmp 0x66f6
cmpl $0x20, %ecx
ja 0x667e
leaq 0x63786(%rip), %rax     # 0x69da8
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%r14), %rax
addq %rax, (%rbx)
jmp 0x66fc
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0x66cf
addl $-0x16, %ecx
cmpl $0x4, %ecx
ja 0x667e
leaq 0x6385e(%rip), %rax     # 0x69eb0
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movsd (%r14), %xmm0
addsd (%rbx), %xmm0
jmp 0x67d9
cmpl $0x16, %ecx
jne 0x667e
movq (%rbx), %rdi
movq (%r14), %rsi
popq %rbx
popq %r14
popq %r15
jmp 0x3370
movq (%r15), %rax
movq (%rax), %rcx
movq 0x20(%rax), %rdi
leaq 0x639ab(%rip), %rsi     # 0x6a03a
xorl %eax, %eax
popq %rbx
popq %r14
popq %r15
jmpq *%rcx
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setg %cl
jmp 0x66f9
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setns %cl
jmp 0x66f9
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setne %cl
jmp 0x66f9
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
shrl $0x1f, %eax
jmp 0x65d8
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setle %cl
movq %rcx, (%rbx)
popq %rbx
popq %r14
popq %r15
retq
movsd (%r14), %xmm0
xorl %eax, %eax
ucomisd (%rbx), %xmm0
jmp 0x6751
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
jmp 0x6727
movsd (%r14), %xmm0
xorl %eax, %eax
ucomisd (%rbx), %xmm0
seta %al
jmp 0x65d8
movsd (%r14), %xmm0
cmpneqsd (%rbx), %xmm0
movq %xmm0, %rax
andl $0x1, %eax
jmp 0x65d8
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
setae %al
jmp 0x65d8
movsd (%r14), %xmm1
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jne 0x6781
jp 0x6781
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x638d3(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movsd (%r14), %xmm1
movsd (%rbx), %xmm0
callq 0x31e0
jmp 0x67d9
movsd (%r14), %xmm0
mulsd (%rbx), %xmm0
jmp 0x67d9
movsd (%r14), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0x67bf
jp 0x67bf
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63895(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movsd (%r14), %xmm0
movsd (%rbx), %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%rbx)
jmp 0x66fc
movsd (%rbx), %xmm0
subsd (%r14), %xmm0
movsd %xmm0, (%rbx)
jmp 0x66fc
movq (%rbx), %rax
imulq (%r14), %rax
jmp 0x65d8
movq (%r14), %rax
xorq %rax, (%rbx)
jmp 0x66fc
movq (%r14), %rax
andq %rax, (%rbx)
jmp 0x66fc
movq (%r14), %rax
subq %rax, (%rbx)
jmp 0x66fc
movq (%r14), %rax
orq %rax, (%rbx)
jmp 0x66fc
movb (%r14), %cl
shlq %cl, (%rbx)
jmp 0x66fc
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0x66a7
movq (%r14), %rcx
testq %rcx, %rcx
jne 0x684f
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63803(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
movq %rax, %rdx
negq %rdx
jno 0x6933
cmpq $-0x1, %rcx
je 0x691b
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
jmp 0x6933
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setl %cl
jmp 0x66f9
movb (%r14), %cl
sarq %cl, (%rbx)
jmp 0x66fc
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0x66f6
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setge %cl
jmp 0x66f9
movq (%r14), %rcx
testq %rcx, %rcx
jne 0x68cc
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63786(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
xorl %edx, %edx
divq %rcx
jmp 0x6938
movb (%r14), %cl
shrq %cl, (%rbx)
jmp 0x66fc
movq (%r14), %rcx
testq %rcx, %rcx
jne 0x68fe
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63754(%rip), %rsi     # 0x6a04b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
movq %rax, %rdx
negq %rdx
jno 0x6958
cmpq $-0x1, %rcx
je 0x6940
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
jmp 0x6958
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x63733(%rip), %rsi     # 0x6a05c
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
cqto
idivq %rcx
movq %rdx, (%rbx)
jmp 0x66fc
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6370e(%rip), %rsi     # 0x6a05c
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
cqto
idivq %rcx
jmp 0x65d8