// File: /workspace/github_c_makefile_star2_O3/vtereshkov[P]umka-lang/src/umka_stmt.c
// Function: parseFnBlock
void parseFnBlock(Compiler *comp, Ident *fn, const Type *upvaluesStructType)
{
    lexEat(&comp->lex, TOK_LBRACE);
    blocksEnterFn(&comp->blocks, fn, upvaluesStructType != NULL);

    const char *prevDebugFnName = comp->lex.debug->fnName;

    if (fn->kind == IDENT_CONST && fn->type->kind == TYPE_FN && fn->block == 0)
    {
        if (fn->type->sig.isMethod)
            comp->lex.debug->fnName = identMethodNameWithRcv(&comp->idents, fn);
        else
            comp->lex.debug->fnName = fn->name;
    }
    else
        comp->lex.debug->fnName = "<unknown>";

    if (fn->prototypeOffset >= 0)
    {
        genEntryPoint(&comp->gen, fn->prototypeOffset);
        fn->prototypeOffset = -1;
    }

    genEnterFrameStub(&comp->gen);

    // Formal parameters
    for (int i = 0; i < fn->type->sig.numParams; i++)
        identAllocParam(&comp->idents, &comp->types, &comp->modules, &comp->blocks, &fn->type->sig, i);

    // Upvalues
    if (upvaluesStructType)
    {
        // Extract upvalues structure from the "any" interface
        const Ident *upvaluesParamIdent = identAssertFind(&comp->idents, &comp->modules, &comp->blocks, comp->blocks.module, "#upvalues", NULL);
        const Type *upvaluesParamType = upvaluesParamIdent->type;

        doPushVarPtr(comp, upvaluesParamIdent);
        genDeref(&comp->gen, upvaluesParamIdent->type->kind);
        doExplicitTypeConv(comp, upvaluesStructType, &upvaluesParamType, NULL);

        // Copy upvalue structure fields to new local variables
        for (int i = 0; i < upvaluesStructType->numItems; i++)
        {
            const Field *upvalue = upvaluesStructType->field[i];

            genDup(&comp->gen);
            genGetFieldPtr(&comp->gen, upvalue->offset);
            genDeref(&comp->gen, upvalue->type->kind);

            const Ident *upvalueIdent = identAllocVar(&comp->idents, &comp->types, &comp->modules, &comp->blocks, upvalue->name, upvalue->type, false);
            doZeroVar(comp, upvalueIdent);
            doPushVarPtr(comp, upvalueIdent);

            genSwapChangeRefCntAssign(&comp->gen, upvalue->type);
        }

        genPop(&comp->gen);
    }

    // 'break'/'continue'/'return' prologs
    Gotos *outerBreaks = comp->gen.breaks;
    comp->gen.breaks = NULL;

    Gotos *outerContinues = comp->gen.continues;
    comp->gen.continues = NULL;

    Gotos returns, *outerReturns = comp->gen.returns;
    comp->gen.returns = &returns;
    genGotosProlog(&comp->gen, comp->gen.returns, blocksCurrent(&comp->blocks));

    // Additional scope embracing StmtList
    blocksEnter(&comp->blocks);

    // StmtList
    parseStmtList(comp);

    const bool hasReturn = comp->blocks.item[comp->blocks.top].hasReturn;

    // Additional scope embracing StmtList
    doGarbageCollection(comp);
    identWarnIfUnusedAll(&comp->idents, blocksCurrent(&comp->blocks));
    blocksLeave(&comp->blocks);

    // 'return'/'continue'/'break' epilogs
    genGotosEpilog(&comp->gen, comp->gen.returns);
    comp->gen.returns = outerReturns;
    comp->gen.continues = outerContinues;
    comp->gen.breaks = outerBreaks;

    doGarbageCollection(comp);
    identWarnIfUnusedAll(&comp->idents, blocksCurrent(&comp->blocks));
    identFree(&comp->idents, blocksCurrent(&comp->blocks));

    const int localVarSlots = align(comp->blocks.item[comp->blocks.top].localVarSize, sizeof(Slot)) / sizeof(Slot);

    const ParamLayout *paramLayout = typeMakeParamLayout(&comp->types, &fn->type->sig);

    genLeaveFrameFixup(&comp->gen, typeMakeParamAndLocalVarLayout(&comp->types, paramLayout, localVarSlots));
    genReturn(&comp->gen, paramLayout->numParamSlots);

    comp->lex.debug->fnName = prevDebugFnName;

    blocksLeave(&comp->blocks);
    lexEat(&comp->lex, TOK_RBRACE);

    if (!hasReturn && fn->type->sig.resultType->kind != TYPE_VOID)
        comp->error.handler(comp->error.context, "Function must return a value");
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x208, %rsp            # imm = 0x208
movq %rdx, %r12
movq %rsi, %r14
movq %rdi, %rbx
addq $0x4ba8, %rdi           # imm = 0x4BA8
movq %rdi, 0x58(%rsp)
movl $0x3c, %esi
callq 0x1637d
leaq 0x4220(%rbx), %r15
xorl %edx, %edx
testq %r12, %r12
setne %dl
movq %r15, %rdi
movq %r14, %rsi
callq 0x850c
movq 0x4e08(%rbx), %rax
movq 0x8(%rax), %rdx
cmpl $0x0, (%r14)
movq %rdx, 0x50(%rsp)
jne 0x17bd0
movq 0x108(%r14), %rcx
cmpl $0x1a, (%rcx)
jne 0x17bd0
cmpl $0x0, 0x114(%r14)
je 0x17f79
leaq 0x5a7d6(%rip), %rcx     # 0x723ad
movq %rcx, 0x8(%rax)
movq %r12, 0x10(%rsp)
movq %r15, 0x18(%rsp)
movl 0x11c(%r14), %esi
testl %esi, %esi
js 0x17c07
leaq 0x4e70(%rbx), %rdi
callq 0x14570
movl $0xffffffff, 0x11c(%r14) # imm = 0xFFFFFFFF
movq %rbx, 0x28(%rsp)
leaq 0x4e70(%rbx), %rdi
movq %rdi, 0x48(%rsp)
callq 0x144cf
movq 0x108(%r14), %r8
cmpl $0x0, 0x28(%r8)
movq %r14, %rbx
movq 0x18(%rsp), %r13
jle 0x17c7c
addq $0x28, %r8
movq 0x28(%rsp), %rax
leaq 0x4e38(%rax), %r14
leaq 0x4e18(%rax), %r15
leaq 0x100(%rax), %rbp
xorl %r12d, %r12d
movq %r14, %rdi
movq %r15, %rsi
movq %rbp, %rdx
movq %r13, %rcx
movl %r12d, %r9d
callq 0x15468
incl %r12d
movq 0x108(%rbx), %rax
leaq 0x28(%rax), %r8
cmpl 0x28(%rax), %r12d
jl 0x17c54
movq %rbx, 0x20(%rsp)
movq 0x10(%rsp), %r12
testq %r12, %r12
movq 0x28(%rsp), %rbx
movq 0x48(%rsp), %r13
je 0x17dbd
leaq 0x4e38(%rbx), %rdi
leaq 0x100(%rbx), %rsi
movl 0x4b88(%rbx), %ecx
leaq 0x5a72c(%rip), %r8      # 0x723e0
movq %rdi, 0x30(%rsp)
movq %rsi, 0x60(%rsp)
movq 0x18(%rsp), %rdx
xorl %r9d, %r9d
callq 0x14c77
movq %rax, %r14
movq 0x108(%rax), %rax
leaq 0x68(%rsp), %r15
movq %rax, (%r15)
movq %rbx, %rdi
movq %r14, %rsi
callq 0xc9da
movq 0x108(%r14), %rax
movl (%rax), %esi
movq %r13, %rdi
callq 0x132bc
movq %rbx, %rdi
movq %r12, %rsi
movq %r15, %rdx
xorl %ecx, %ecx
callq 0xd1ae
cmpl $0x0, 0x10(%r12)
jle 0x17db5
leaq 0x4e18(%rbx), %r15
xorl %ebp, %ebp
movq 0x28(%r12), %rax
movq (%rax,%rbp,8), %r14
movq %r13, %rdi
callq 0x13273
movl 0x110(%r14), %esi
movq %r13, %rdi
callq 0x13a27
movq 0x108(%r14), %rax
movl (%rax), %esi
movq %r13, %rdi
callq 0x132bc
movq 0x108(%r14), %r9
movl $0x0, (%rsp)
movq 0x30(%rsp), %rdi
movq %r15, %rsi
movq 0x60(%rsp), %rdx
movq 0x18(%rsp), %rcx
movq %r14, %r8
callq 0x152ff
movq %rax, %r12
movq %rbx, %rdi
movq %rax, %rsi
callq 0x17011
movq %rbx, %rdi
movq %r12, %rsi
movq 0x10(%rsp), %r12
callq 0xc9da
movq 0x108(%r14), %rsi
movq %r13, %rdi
callq 0x1362e
incq %rbp
movslq 0x10(%r12), %rax
cmpq %rax, %rbp
jl 0x17d1e
movq %r13, %rdi
callq 0x131c1
movq 0x5028(%rbx), %r12
leaq 0x68(%rsp), %r15
movq %r15, 0x5028(%rbx)
leaq 0x4e38(%rbx), %r14
movups 0x5018(%rbx), %xmm0
movaps %xmm0, 0x30(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x5018(%rbx)
movq 0x18(%rsp), %rbp
movq %rbp, %rdi
callq 0x85bf
movq %r13, %rdi
movq %r15, %rsi
movl %eax, %edx
callq 0x145d6
movq %rbp, %rdi
callq 0x8503
movq %rbx, %rdi
callq 0x17fa7
movslq 0x4b84(%rbx), %rsi
leaq (%rsi,%rsi,2), %rax
movb 0x14(%rbp,%rax,8), %al
movb %al, 0x10(%rsp)
movq %rbx, %rdi
callq 0x16e8c
movq %rbp, %rdi
callq 0x85bf
movq %r14, %rdi
movl %eax, %esi
callq 0x1559f
movq %rbp, %rdi
callq 0x8584
movq 0x5028(%rbx), %rsi
movq %r13, %rdi
callq 0x1464c
movq %r12, 0x5028(%rbx)
movaps 0x30(%rsp), %xmm0
movups %xmm0, 0x5018(%rbx)
movl 0x4b84(%rbx), %esi
movq %rbx, %rdi
callq 0x16e8c
movq %rbp, %rdi
callq 0x85bf
movq %r14, %rdi
movl %eax, %esi
callq 0x1559f
movq %rbp, %rdi
callq 0x85bf
movq %r14, %rdi
movl %eax, %esi
callq 0x14a1a
movslq 0x4b84(%rbx), %rax
leaq (%rax,%rax,2), %rax
movslq 0x10(%rbp,%rax,8), %r14
leaq 0x7(%r14), %rax
addq $0xe, %r14
testq %rax, %rax
cmovnsq %rax, %r14
shrq $0x3, %r14
leaq 0x4e18(%rbx), %r15
movq 0x20(%rsp), %rax
movq 0x108(%rax), %rsi
addq $0x28, %rsi
movq %r15, %rdi
callq 0x1acd0
movq %rax, %r12
movq %r15, %rdi
movq %rax, %rsi
movl %r14d, %edx
callq 0x1ad8b
movq %r13, %rdi
movq %rax, %rsi
callq 0x14510
movl 0x10(%r12), %esi
movq %r13, %rdi
callq 0x13ebd
movq 0x4e08(%rbx), %rax
movq 0x50(%rsp), %rcx
movq %rcx, 0x8(%rax)
movq %rbp, %rdi
callq 0x8584
movq 0x58(%rsp), %rdi
movl $0x3d, %esi
callq 0x1637d
cmpb $0x0, 0x10(%rsp)
jne 0x17f67
movq 0x20(%rsp), %rax
movq 0x108(%rax), %rax
movq 0xb8(%rax), %rax
cmpl $0x2, (%rax)
je 0x17f67
movq 0x5118(%rbx), %rdi
leaq 0x5f78d(%rip), %rsi     # 0x776ec
xorl %eax, %eax
callq *0x50f8(%rbx)
addq $0x208, %rsp            # imm = 0x208
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
cmpb $0x1, 0x30(%rcx)
jne 0x17f9e
leaq 0x4e38(%rbx), %rdi
movq %r14, %rsi
callq 0x154db
movq 0x4e08(%rbx), %rcx
movq %rax, 0x8(%rcx)
jmp 0x17bdb
leaq 0x4(%r14), %rcx
jmp 0x17bd7