// File: /workspace/github_c_makefile_star2_O1/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 0xf1a6
leaq 0x67b96(%rip), %rsi     # 0x76cfc
movslq (%rsi,%rdx,4), %rdx
addq %rsi, %rdx
jmpq *%rdx
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xf3ca
leaq 0x67b96(%rip), %rax     # 0x76d18
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xf24c
movl %eax, %edx
andl $-0x2, %edx
cmpl $0xe, %edx
jne 0xf254
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0xf38f
leaq 0x67cfd(%rip), %rcx     # 0x76ec4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movsd (%r14), %xmm0
cmpeqsd (%rbx), %xmm0
jmp 0xf485
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xf3ca
leaq 0x67b92(%rip), %rax     # 0x76d84
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
leal -0x2e(%rcx), %eax
cmpl $0x8, %eax
ja 0xf3b5
leaq 0x67b2e(%rip), %rcx     # 0x76d3c
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 0xf24c
addl $-0x2e, %ecx
cmpl $0x8, %ecx
ja 0xf3ca
leaq 0x67b25(%rip), %rax     # 0x76d60
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
sete %cl
jmp 0xf445
addl $-0x16, %ecx
cmpl $0xb, %eax
jne 0xf362
cmpl $0x20, %ecx
ja 0xf3ca
leaq 0x67bbc(%rip), %rax     # 0x76e2c
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
cmpq $0x0, (%r14)
jne 0xf291
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67dbe(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
movq (%rbx), %rax
xorl %edx, %edx
divq (%r14)
jmp 0xf324
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
seta %cl
jmp 0xf445
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setae %cl
jmp 0xf445
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setb %cl
jmp 0xf445
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setbe %cl
jmp 0xf445
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xf3f3
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
notq %rax
jmp 0xf320
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
shrq $0x3f, %rax
movq %rax, (%rbx)
jmp 0xf448
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xf41b
movq %r15, %rdi
movq %rbx, %rsi
movq %r14, %rdx
movq %r8, %rcx
callq 0xf663
xorl %ecx, %ecx
testq %rax, %rax
jmp 0xf442
cmpl $0x20, %ecx
ja 0xf3ca
leaq 0x67a3a(%rip), %rax     # 0x76da8
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movq (%r14), %rax
addq %rax, (%rbx)
jmp 0xf448
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xf41b
addl $-0x16, %ecx
cmpl $0x4, %ecx
ja 0xf3ca
leaq 0x67b12(%rip), %rax     # 0x76eb0
movslq (%rax,%rcx,4), %rcx
addq %rax, %rcx
jmpq *%rcx
movsd (%r14), %xmm0
addsd (%rbx), %xmm0
jmp 0xf51a
cmpl $0x16, %ecx
jne 0xf3ca
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 0x67c5f(%rip), %rsi     # 0x7703a
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 0xf445
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setns %cl
jmp 0xf445
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
xorl %ecx, %ecx
testl %eax, %eax
setne %cl
jmp 0xf445
movq (%rbx), %rdi
movq (%r14), %rsi
callq 0x3210
shrl $0x1f, %eax
jmp 0xf324
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 0xf49d
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
jmp 0xf473
movsd (%r14), %xmm0
xorl %eax, %eax
ucomisd (%rbx), %xmm0
seta %al
jmp 0xf324
movsd (%r14), %xmm0
cmpneqsd (%rbx), %xmm0
movq %xmm0, %rax
andl $0x1, %eax
jmp 0xf324
movsd (%rbx), %xmm0
xorl %eax, %eax
ucomisd (%r14), %xmm0
setae %al
jmp 0xf324
movsd (%r14), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xf4c8
jp 0xf4c8
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67b87(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
movsd (%rbx), %xmm0
movsd (%r14), %xmm1
callq 0x31e0
jmp 0xf51a
movsd (%r14), %xmm0
mulsd (%rbx), %xmm0
jmp 0xf51a
movsd (%r14), %xmm0
xorpd %xmm1, %xmm1
ucomisd %xmm1, %xmm0
jne 0xf506
jp 0xf506
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67b49(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
movsd (%rbx), %xmm0
divsd (%r14), %xmm0
jmp 0xf51a
movsd (%rbx), %xmm0
subsd (%r14), %xmm0
movsd %xmm0, (%rbx)
jmp 0xf448
movq (%rbx), %rax
imulq (%r14), %rax
jmp 0xf324
movq (%r14), %rax
xorq %rax, (%rbx)
jmp 0xf448
movq (%r14), %rax
andq %rax, (%rbx)
jmp 0xf448
movq (%r14), %rax
subq %rax, (%rbx)
jmp 0xf448
movq (%r14), %rax
orq %rax, (%rbx)
jmp 0xf448
movb (%r14), %cl
shlq %cl, (%rbx)
jmp 0xf448
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xf3f3
cmpq $0x0, (%r14)
jne 0xf58b
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67ac4(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
xorl %eax, %eax
cmpq (%rbx), %rax
jno 0xf5aa
cmpq $-0x1, (%r14)
jne 0xf5aa
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67ab6(%rip), %rsi     # 0x7705c
xorl %eax, %eax
callq *(%rcx)
movq (%rbx), %rax
cqto
idivq (%r14)
jmp 0xf60c
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setl %cl
jmp 0xf445
movb (%r14), %cl
sarq %cl, (%rbx)
jmp 0xf448
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
jmp 0xf442
movq (%rbx), %rax
xorl %ecx, %ecx
cmpq (%r14), %rax
setge %cl
jmp 0xf445
cmpq $0x0, (%r14)
jne 0xf604
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67a4b(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
movq (%rbx), %rax
xorl %edx, %edx
divq (%r14)
movq %rdx, (%rbx)
jmp 0xf448
movb (%r14), %cl
shrq %cl, (%rbx)
jmp 0xf448
cmpq $0x0, (%r14)
jne 0xf637
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67a18(%rip), %rsi     # 0x7704b
xorl %eax, %eax
callq *(%rcx)
xorl %eax, %eax
cmpq (%rbx), %rax
jno 0xf656
cmpq $-0x1, (%r14)
jne 0xf656
movq (%r15), %rcx
movq 0x20(%rcx), %rdi
leaq 0x67a0a(%rip), %rsi     # 0x7705c
xorl %eax, %eax
callq *(%rcx)
movq (%rbx), %rax
cqto
idivq (%r14)
jmp 0xf324