// File: /workspace/github_c_makefile_star2_O1/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 %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x18, %rsp
movl %esi, %r8d
movq %rdi, %rbx
movslq 0x8(%rdi), %rax
movl 0x1a4(%rdi), %ecx
cmpl %ecx, %eax
jle 0x18d3a
movq (%rbx), %rdx
movq %rax, %rsi
shlq $0x5, %rsi
leaq (%rdx,%rsi), %r12
addq $-0x20, %r12
jmp 0x18d3d
xorl %r12d, %r12d
leal -0x2(%rax), %edx
cmpl %ecx, %edx
jge 0x18d48
xorl %ecx, %ecx
jmp 0x18d52
movslq %edx, %rcx
shlq $0x5, %rcx
addq (%rbx), %rcx
testq %r12, %r12
je 0x18e11
cmpl $0x1, (%r12)
jne 0x18e11
xorl %r14d, %r14d
cmpl $0x0, 0x4(%r12)
jne 0x18e14
movq %r14, (%rsp)
movq %r14, 0x8(%rsp)
leal -0x6(%r8), %edx
cmpl $0xe, %edx
ja 0x18dc3
leaq 0x5f252(%rip), %rsi     # 0x77fe0
movslq (%rsi,%rdx,4), %rdx
addq %rsi, %rdx
jmpq *%rdx
movsd 0x18(%r12), %xmm0
movsd %xmm0, (%rsp)
leal -0x8(%r8), %eax
movl $0x7, %r14d
cmpl $0x3, %eax
jb 0x18dc3
xorl %eax, %eax
cmpl $0xb, %r8d
setne %al
leal 0x7(,%rax,8), %r14d
testl %r14d, %r14d
je 0x18e11
movq 0x1e0(%rbx), %rax
leaq 0x10(%rsp), %rdi
movq %rax, (%rdi)
movl 0xc(%r12), %ecx
movq %rsp, %r15
leaq 0x8(%rsp), %rdx
movq %r15, %rsi
callq 0xf7f6
movl %r14d, 0xc(%r12)
movq (%r15), %rax
movq %rax, 0x18(%r12)
movl $0x0, 0x1d8(%rbx)
movl 0x8(%rbx), %eax
movl %eax, 0x1dc(%rbx)
movb $0x1, %r14b
jmp 0x18e14
xorl %r14d, %r14d
movl %r14d, %eax
addq $0x18, %rsp
popq %rbx
popq %r12
popq %r14
popq %r15
retq
movq 0x18(%r12), %rax
movq %rax, (%rsp)
movl $0x7, %r14d
jmp 0x18dc3
movq 0x18(%r12), %rax
movq %rax, (%rsp)
movl $0xf, %r14d
jmp 0x18dc3
testq %rcx, %rcx
je 0x18dc3
cmpl $0x1, (%rcx)
jne 0x18dc3
cmpl $0x0, 0x4(%rcx)
jne 0x18dc3
movq 0x18(%rcx), %rax
movq %rax, (%rsp)
jmp 0x18eb6
testq %rcx, %rcx
je 0x18dc3
cmpl $0x1, (%rcx)
jne 0x18dc3
cmpl $0x0, 0x4(%rcx)
jne 0x18dc3
movsd 0x18(%rcx), %xmm0
movsd %xmm0, (%rsp)
movsd 0x18(%r12), %xmm0
movsd %xmm0, 0x8(%rsp)
decl %eax
movl %eax, 0x8(%rbx)
movl $0x0, 0x1d8(%rbx)
movl %eax, 0x1dc(%rbx)
movl $0xf, %r14d
movq %rcx, %r12
jmp 0x18dc3