// File: /workspace/github_c_makefile_star2_O2/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 $0x1f8, %rsp            # imm = 0x1F8
movq %rdx, %rbx
movq %rsi, %r14
movq %rdi, %rbp
addq $0x4ba8, %rdi           # imm = 0x4BA8
pushq $0x3c
popq %rsi
movq %rdi, 0x48(%rsp)
callq 0x118d3
leaq 0x4220(%rbp), %r15
xorl %edx, %edx
movq %rbx, 0x10(%rsp)
testq %rbx, %rbx
setne %dl
movq %r15, %rdi
movq %r14, %rsi
callq 0x4b1c
movq 0x4e08(%rbp), %rax
movq 0x8(%rax), %rcx
movq %rcx, 0x40(%rsp)
cmpl $0x0, (%r14)
jne 0x13035
movq 0x108(%r14), %rcx
cmpl $0x1a, (%rcx)
jne 0x13035
cmpl $0x0, 0x114(%r14)
je 0x13397
leaq 0x53371(%rip), %rcx     # 0x663ad
movq %rcx, 0x8(%rax)
movl 0x11c(%r14), %esi
testl %esi, %esi
js 0x1305f
leaq 0x4e70(%rbp), %rdi
callq 0xfd33
orl $-0x1, 0x11c(%r14)
leaq 0x4e70(%rbp), %r13
movq %r13, %rdi
callq 0xfceb
leaq 0x4e38(%rbp), %rax
movq %rax, 0x18(%rsp)
leaq 0x4e18(%rbp), %rax
movq %rax, 0x28(%rsp)
leaq 0x100(%rbp), %rbx
xorl %r12d, %r12d
movq 0x108(%r14), %r8
cmpl 0x28(%r8), %r12d
jge 0x130be
addq $0x28, %r8
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq %rbx, %rdx
movq %r15, %rcx
movl %r12d, %r9d
callq 0x10b4f
incl %r12d
jmp 0x13090
movq %r14, 0x50(%rsp)
cmpq $0x0, 0x10(%rsp)
movq %r15, 0x20(%rsp)
je 0x131f4
movl 0x4b88(%rbp), %ecx
leaq 0x532ff(%rip), %r8      # 0x663e0
movq %rbp, %r14
xorl %ebp, %ebp
movq 0x18(%rsp), %rdi
movq %rbx, %rsi
movq %r15, %rdx
xorl %r9d, %r9d
callq 0x103e6
movq %rax, %r12
movq 0x108(%rax), %rax
leaq 0x58(%rsp), %r15
movq %rax, (%r15)
movq %r14, %rdi
movq %r12, %rsi
callq 0x8c92
movq 0x108(%r12), %rax
movl (%rax), %esi
movq %r13, %rdi
callq 0xee17
movq %r14, 0x30(%rsp)
movq %r14, %rdi
movq 0x10(%rsp), %r14
movq %r14, %rsi
movq %r15, %rdx
xorl %ecx, %ecx
callq 0x97e0
movq 0x30(%rsp), %r15
movslq 0x10(%r14), %rax
cmpq %rax, %rbp
jge 0x131e2
movq 0x28(%r14), %rax
movq (%rax,%rbp,8), %r12
movq %r13, %rdi
callq 0xedd1
movl 0x110(%r12), %esi
movq %r13, %rdi
callq 0xf4db
movq 0x108(%r12), %rax
movl (%rax), %esi
movq %r13, %rdi
callq 0xee17
movq 0x108(%r12), %r9
andl $0x0, (%rsp)
movq 0x18(%rsp), %rdi
movq 0x28(%rsp), %rsi
movq %rbx, %rdx
movq 0x20(%rsp), %rcx
movq %r12, %r8
callq 0x10a24
movq %rax, %r14
movq %r15, %rdi
movq %rax, %rsi
callq 0x124c6
movq %r15, %rdi
movq %r14, %rsi
movq 0x10(%rsp), %r14
callq 0x8c92
movq 0x108(%r12), %rsi
movq %r13, %rdi
callq 0xf122
incq %rbp
jmp 0x13147
movq %r13, %rdi
callq 0xed28
movq 0x30(%rsp), %rbp
movq 0x20(%rsp), %r15
movq 0x5028(%rbp), %r14
leaq 0x58(%rsp), %rbx
movq %rbx, 0x5028(%rbp)
movups 0x5018(%rbp), %xmm0
movaps %xmm0, 0x30(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, 0x5018(%rbp)
movq %r15, %rdi
callq 0x4bcc
movq %r13, %rdi
movq %rbx, %rsi
movl %eax, %edx
callq 0xfd7f
movq %r15, %rdi
callq 0x4b13
movq %rbp, %rdi
callq 0x133c5
movslq 0x4b84(%rbp), %rax
imulq $0x18, %rax, %rax
movb 0x14(%r15,%rax), %al
movb %al, 0x10(%rsp)
movq %rbp, %rdi
callq 0x12350
movq %r15, %rdi
callq 0x4bcc
movq 0x18(%rsp), %rbx
movq %rbx, %rdi
movl %eax, %esi
callq 0x10c75
movq %r15, %rdi
callq 0x4b91
movq 0x5028(%rbp), %rsi
movq %r13, %rdi
callq 0xfde1
movq %r14, 0x5028(%rbp)
movaps 0x30(%rsp), %xmm0
movups %xmm0, 0x5018(%rbp)
movq %rbp, %rdi
callq 0x12350
movq %r15, %rdi
callq 0x4bcc
movq %rbx, %rdi
movl %eax, %esi
callq 0x10c75
movq %r15, %rdi
callq 0x4bcc
movq %rbx, %rdi
movl %eax, %esi
callq 0x1018b
movslq 0x4b84(%rbp), %rax
imulq $0x18, %rax, %rax
movslq 0x10(%r15,%rax), %rax
addq $0x7, %rax
pushq $0x8
popq %rcx
cqto
idivq %rcx
movq %rax, %rbx
movq 0x50(%rsp), %r15
movq 0x108(%r15), %rsi
addq $0x28, %rsi
movq 0x28(%rsp), %r12
movq %r12, %rdi
callq 0x15f55
movq %rax, %r14
movq %r12, %rdi
movq %rax, %rsi
movl %ebx, %edx
callq 0x15ff7
movq %r13, %rdi
movq %rax, %rsi
callq 0xfcfd
movl 0x10(%r14), %esi
movq %r13, %rdi
callq 0xf937
movq 0x4e08(%rbp), %rax
movq 0x40(%rsp), %rcx
movq %rcx, 0x8(%rax)
movq 0x20(%rsp), %rdi
callq 0x4b91
pushq $0x3d
popq %rsi
movq 0x48(%rsp), %rdi
callq 0x118d3
cmpb $0x0, 0x10(%rsp)
jne 0x13385
movq 0x108(%r15), %rax
movq 0xb8(%rax), %rax
cmpl $0x2, (%rax)
je 0x13385
movq 0x5118(%rbp), %rdi
leaq 0x5830f(%rip), %rsi     # 0x6b68c
xorl %eax, %eax
callq *0x50f8(%rbp)
addq $0x1f8, %rsp            # imm = 0x1F8
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
cmpb $0x1, 0x30(%rcx)
jne 0x133bc
leaq 0x4e38(%rbp), %rdi
movq %r14, %rsi
callq 0x10bb1
movq 0x4e08(%rbp), %rcx
movq %rax, 0x8(%rcx)
jmp 0x13040
leaq 0x4(%r14), %rcx
jmp 0x1303c