// File: /workspace/github_c_makefile_star2_O0/vtereshkov[P]umka-lang/src/umka_gen.c
// Function: optimizeCallBuiltin
static bool optimizeCallBuiltin(CodeGen *gen, TypeKind typeKind, BuiltinFunc builtin)
{
    Instruction *prev = getPrevInstr(gen, 1), *prev2 = getPrevInstr(gen, 2);

    // Optimization: PUSH + CALL_BUILTIN -> PUSH
    if (prev && prev->opcode == OP_PUSH && prev->inlineOpcode == OP_NOP)
    {
        Const arg = {0}, arg2 = {0};
        TypeKind resultTypeKind = TYPE_NONE;

        switch (builtin)
        {
            case BUILTIN_REAL:
            {
                arg.intVal = prev->operand.intVal;
                resultTypeKind = TYPE_REAL;
                break;
            }
            case BUILTIN_REAL_LHS:
            {
                if (prev2 && prev2->opcode == OP_PUSH && prev2->inlineOpcode == OP_NOP)
                {
                    arg.intVal = prev2->operand.intVal;
                    resultTypeKind = TYPE_REAL;
                    prev = prev2;
                }
                break;
            }
            case BUILTIN_ABS:
            {
                arg.intVal = prev->operand.intVal;
                resultTypeKind = TYPE_INT;
                break;
            }
            case BUILTIN_ROUND:
            case BUILTIN_TRUNC:
            case BUILTIN_CEIL:
            case BUILTIN_FLOOR:
            case BUILTIN_FABS:
            case BUILTIN_SQRT:
            case BUILTIN_SIN:
            case BUILTIN_COS:
            case BUILTIN_ATAN:
            case BUILTIN_EXP:
            case BUILTIN_LOG:
            {
                arg.realVal = prev->operand.realVal;
                resultTypeKind = (builtin == BUILTIN_ROUND || builtin == BUILTIN_TRUNC || builtin == BUILTIN_CEIL || builtin == BUILTIN_FLOOR) ? TYPE_INT : TYPE_REAL;
                break;
            }
            case BUILTIN_ATAN2:
            {
                if (prev2 && prev2->opcode == OP_PUSH && prev2->inlineOpcode == OP_NOP)
                {
                    arg.realVal = prev2->operand.realVal;
                    arg2.realVal = prev->operand.realVal;

                    resultTypeKind = TYPE_REAL;
                    prev = prev2;
                    genRemoveInstr(gen);
                }
                break;
            }
            default: break;
        }

        if (resultTypeKind != TYPE_NONE)
        {
            Consts consts = {.error = gen->error};
            constCallBuiltin(&consts, &arg, &arg2, prev->typeKind, builtin);

            prev->typeKind = resultTypeKind;

            if (resultTypeKind == TYPE_REAL)
                prev->operand.realVal = arg.realVal;
            else
                prev->operand.intVal = arg.intVal;

            genUnnotify(gen);
            return true;
        }
    }

    return false;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x60, %rsp
movq %rdi, -0x10(%rbp)
movl %esi, -0x14(%rbp)
movl %edx, -0x18(%rbp)
movq -0x10(%rbp), %rdi
movl $0x1, %esi
callq 0x18c30
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
movl $0x2, %esi
callq 0x18c30
movq %rax, -0x28(%rbp)
cmpq $0x0, -0x20(%rbp)
je 0x182c7
movq -0x20(%rbp), %rax
cmpl $0x1, (%rax)
jne 0x182c7
movq -0x20(%rbp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x182c7
movq $0x0, -0x30(%rbp)
movq $0x0, -0x38(%rbp)
movl $0x0, -0x3c(%rbp)
movl -0x18(%rbp), %eax
addl $-0x6, %eax
movl %eax, %ecx
movq %rcx, -0x50(%rbp)
subl $0xe, %eax
ja 0x18257
movq -0x50(%rbp), %rax
leaq 0x1c0ecd(%rip), %rcx    # 0x1d9010
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x30(%rbp)
movl $0xf, -0x3c(%rbp)
jmp 0x18259
cmpq $0x0, -0x28(%rbp)
je 0x18199
movq -0x28(%rbp), %rax
cmpl $0x1, (%rax)
jne 0x18199
movq -0x28(%rbp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x18199
movq -0x28(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x30(%rbp)
movl $0xf, -0x3c(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
jmp 0x18259
movq -0x20(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x30(%rbp)
movl $0x7, -0x3c(%rbp)
jmp 0x18259
movq -0x20(%rbp), %rax
movsd 0x18(%rax), %xmm0
movsd %xmm0, -0x30(%rbp)
movb $0x1, %al
cmpl $0x8, -0x18(%rbp)
movb %al, -0x51(%rbp)
je 0x181ef
movb $0x1, %al
cmpl $0x9, -0x18(%rbp)
movb %al, -0x51(%rbp)
je 0x181ef
movb $0x1, %al
cmpl $0xa, -0x18(%rbp)
movb %al, -0x51(%rbp)
je 0x181ef
cmpl $0xb, -0x18(%rbp)
sete %al
movb %al, -0x51(%rbp)
movb -0x51(%rbp), %dl
movl $0xf, %eax
movl $0x7, %ecx
testb $0x1, %dl
cmovnel %ecx, %eax
movl %eax, -0x3c(%rbp)
jmp 0x18259
cmpq $0x0, -0x28(%rbp)
je 0x18255
movq -0x28(%rbp), %rax
cmpl $0x1, (%rax)
jne 0x18255
movq -0x28(%rbp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x18255
movq -0x28(%rbp), %rax
movsd 0x18(%rax), %xmm0
movsd %xmm0, -0x30(%rbp)
movq -0x20(%rbp), %rax
movsd 0x18(%rax), %xmm0
movsd %xmm0, -0x38(%rbp)
movl $0xf, -0x3c(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x20(%rbp)
movq -0x10(%rbp), %rdi
callq 0x18c80
jmp 0x18259
jmp 0x18259
cmpl $0x0, -0x3c(%rbp)
je 0x182c5
movq -0x10(%rbp), %rax
movq 0x1e0(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x20(%rbp), %rax
movl 0xc(%rax), %ecx
movl -0x18(%rbp), %r8d
leaq -0x48(%rbp), %rdi
leaq -0x30(%rbp), %rsi
leaq -0x38(%rbp), %rdx
callq 0x9390
movl -0x3c(%rbp), %ecx
movq -0x20(%rbp), %rax
movl %ecx, 0xc(%rax)
cmpl $0xf, -0x3c(%rbp)
jne 0x182aa
movsd -0x30(%rbp), %xmm0
movq -0x20(%rbp), %rax
movsd %xmm0, 0x18(%rax)
jmp 0x182b6
movq -0x30(%rbp), %rcx
movq -0x20(%rbp), %rax
movq %rcx, 0x18(%rax)
movq -0x10(%rbp), %rdi
callq 0x16740
movb $0x1, -0x1(%rbp)
jmp 0x182cb
jmp 0x182c7
movb $0x0, -0x1(%rbp)
movb -0x1(%rbp), %al
andb $0x1, %al
addq $0x60, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)