// File: /workspace/github_c_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %rbx
subq $0x18, %rsp
movl %esi, %r8d
movq %rdi, %rbx
movslq 0x8(%rdi), %rax
movl 0x1a4(%rdi), %ecx
cmpl %ecx, %eax
jle 0xf7a7
movq (%rbx), %rdx
movq %rax, %rsi
shlq $0x5, %rsi
leaq (%rdx,%rsi), %r15
addq $-0x20, %r15
jmp 0xf7aa
xorl %r15d, %r15d
leal -0x2(%rax), %edx
cmpl %ecx, %edx
jge 0xf7b5
xorl %ecx, %ecx
jmp 0xf7bf
movslq %edx, %rcx
shlq $0x5, %rcx
addq (%rbx), %rcx
testq %r15, %r15
je 0xf7d1
cmpl $0x1, (%r15)
jne 0xf7d1
cmpl $0x0, 0x4(%r15)
je 0xf7de
xorl %eax, %eax
addq $0x18, %rsp
popq %rbx
popq %r14
popq %r15
popq %rbp
retq
andq $0x0, 0x8(%rsp)
leal -0x6(%r8), %edx
cmpl $0xe, %edx
ja 0xf7d1
leaq 0x5b78c(%rip), %rsi     # 0x6af80
movslq (%rsi,%rdx,4), %rdx
addq %rsi, %rdx
jmpq *%rdx
movsd 0x18(%r15), %xmm0
movsd %xmm0, (%rsp)
leal -0x8(%r8), %eax
cmpl $0x3, %eax
jae 0xf816
pushq $0x7
popq %rbp
jmp 0xf826
xorl %eax, %eax
cmpl $0xb, %r8d
setne %al
leal 0x7(,%rax,8), %ebp
movq 0x1e0(%rbx), %rax
leaq 0x10(%rsp), %rdi
movq %rax, (%rdi)
movl 0xc(%r15), %ecx
movq %rsp, %r14
leaq 0x8(%rsp), %rdx
movq %r14, %rsi
callq 0x6aed
movl %ebp, 0xc(%r15)
movq (%r14), %rax
movq %rax, 0x18(%r15)
andl $0x0, 0x1d8(%rbx)
movl 0x8(%rbx), %eax
movl %eax, 0x1dc(%rbx)
movb $0x1, %al
jmp 0xf7d3
movq 0x18(%r15), %rax
movq %rax, (%rsp)
jmp 0xf811
movq 0x18(%r15), %rax
movq %rax, (%rsp)
pushq $0xf
jmp 0xf813
testq %rcx, %rcx
je 0xf7d1
cmpl $0x1, (%rcx)
jne 0xf7d1
cmpl $0x0, 0x4(%rcx)
jne 0xf7d1
movq 0x18(%rcx), %rax
movq %rax, (%rsp)
jmp 0xf8eb
testq %rcx, %rcx
je 0xf7d1
cmpl $0x1, (%rcx)
jne 0xf7d1
cmpl $0x0, 0x4(%rcx)
jne 0xf7d1
movsd 0x18(%rcx), %xmm0
movsd %xmm0, (%rsp)
movsd 0x18(%r15), %xmm0
movsd %xmm0, 0x8(%rsp)
decl %eax
movl %eax, 0x8(%rbx)
andl $0x0, 0x1d8(%rbx)
movl %eax, 0x1dc(%rbx)
pushq $0xf
popq %rbp
movq %rcx, %r15
jmp 0xf826