// File: /workspace/github_c_makefile_star2_O3/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 0x9f7e
leaq 0x6bdbe(%rip), %rsi     # 0x75cfc
movslq (%rsi,%rdx,4), %rdx
addq %rsi, %rdx
jmpq *%rdx
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xa1a7
leaq 0x6bdbe(%rip), %rax     # 0x75d18
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xa024
movl %eax, %edx
andl $-0x2, %edx
cmpl $0xe, %edx
jne 0xa02c
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0xa16c
leaq 0x6bf25(%rip), %rcx     # 0x75ec4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movsd (%r14), %xmm0
cmpeqsd (%rbx), %xmm0
jmp 0xa262
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xa1a7
leaq 0x6bdba(%rip), %rax     # 0x75d84
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0xa192
leaq 0x6bd56(%rip), %rcx     # 0x75d3c
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 0xa024
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xa1a7
leaq 0x6bd4d(%rip), %rax     # 0x75d60
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
sete %cl
jmp 0xa222
addl $-0x16, %ecx
cmpl $0xb, %eax
jne 0xa13f
cmpl $0x20, %ecx
ja 0xa1a7
leaq 0x6bde4(%rip), %rax     # 0x75e2c
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%r14), %rcx
testq %rcx, %rcx
jne 0xa06e
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bfe4(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
xorl %edx, %edx
divq %rcx
jmp 0xa101
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
seta %cl
jmp 0xa222
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setae %cl
jmp 0xa222
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setb %cl
jmp 0xa222
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setbe %cl
jmp 0xa222
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xa1d0
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
notq %rax
jmp 0xa0fd
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
shrq $0x3f, %rax
movq %rax, (%rbx)
jmp 0xa225
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xa1f8
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xa48b
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xa21f
cmpl $0x20, %ecx
ja 0xa1a7
leaq 0x6bc5d(%rip), %rax     # 0x75da8
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%r14), %rax
addq %rax, (%rbx)
jmp 0xa225
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xa1f8
addl $-0x16, %ecx
cmpl $0x4, %ecx
ja 0xa1a7
leaq 0x6bd35(%rip), %rax     # 0x75eb0
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movsd (%r14), %xmm0
addsd (%rbx), %xmm0
jmp 0xa302
cmpl $0x16, %ecx
jne 0xa1a7
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 0x6be82(%rip), %rsi     # 0x7603a
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 0xa222
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setns %cl
jmp 0xa222
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setne %cl
jmp 0xa222
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
shrl $0x1f, %eax
jmp 0xa101
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 0xa27a
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
jmp 0xa250
movsd (%r14), %xmm0
xorl %eax, %eax
ucomisd (%rbx), %xmm0
seta %al
jmp 0xa101
movsd (%r14), %xmm0
cmpneqsd (%rbx), %xmm0
movq %xmm0, %rax
andl $0x1, %eax
jmp 0xa101
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
setae %al
jmp 0xa101
movsd (%r14), %xmm1
xorpd %xmm0, %xmm0
ucomisd %xmm0, %xmm1
jne 0xa2aa
jp 0xa2aa
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bdaa(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movsd (%r14), %xmm1
movsd (%rbx), %xmm0
callq 0x31e0
jmp 0xa302
movsd (%r14), %xmm0
mulsd (%rbx), %xmm0
jmp 0xa302
movsd (%r14), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xa2e8
jp 0xa2e8
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bd6c(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movsd (%r14), %xmm0
movsd (%rbx), %xmm1
divsd %xmm0, %xmm1
movsd %xmm1, (%rbx)
jmp 0xa225
movsd (%rbx), %xmm0
subsd (%r14), %xmm0
movsd %xmm0, (%rbx)
jmp 0xa225
movq (%rbx), %rax
imulq (%r14), %rax
jmp 0xa101
movq (%r14), %rax
xorq %rax, (%rbx)
jmp 0xa225
movq (%r14), %rax
andq %rax, (%rbx)
jmp 0xa225
movq (%r14), %rax
subq %rax, (%rbx)
jmp 0xa225
movq (%r14), %rax
orq %rax, (%rbx)
jmp 0xa225
movb (%r14), %cl
shlq %cl, (%rbx)
jmp 0xa225
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xa1d0
movq (%r14), %rcx
testq %rcx, %rcx
jne 0xa378
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bcda(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
movq %rax, %rdx
negq %rdx
jno 0xa45c
cmpq $-0x1, %rcx
je 0xa444
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
jmp 0xa45c
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setl %cl
jmp 0xa222
movb (%r14), %cl
sarq %cl, (%rbx)
jmp 0xa225
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xa21f
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setge %cl
jmp 0xa222
movq (%r14), %rcx
testq %rcx, %rcx
jne 0xa3f5
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bc5d(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
xorl %edx, %edx
divq %rcx
jmp 0xa461
movb (%r14), %cl
shrq %cl, (%rbx)
jmp 0xa225
movq (%r14), %rcx
testq %rcx, %rcx
jne 0xa427
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bc2b(%rip), %rsi     # 0x7604b
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
movq %rax, %rdx
negq %rdx
jno 0xa481
cmpq $-0x1, %rcx
je 0xa469
movabsq $-0x8000000000000000, %rax # imm = 0x8000000000000000
jmp 0xa481
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bc0a(%rip), %rsi     # 0x7605c
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
cqto
idivq %rcx
movq %rdx, (%rbx)
jmp 0xa225
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x6bbe5(%rip), %rsi     # 0x7605c
xorl %eax, %eax
callq *(%rcx)
movq (%r14), %rcx
movq (%rbx), %rax
cqto
idivq %rcx
jmp 0xa101