// File: /workspace/github_c_makefile_star2_O1/yangtau[P]hedgehog/src/test/../vm.c
// Function: hg_vm_execute
struct hg_value hg_vm_execute(struct hg_vm_state* vm, struct hg_function* func) {
    hg_stk_ptr sp = vm->stack;

    struct hg_call_frame* cur_frame = vm->frames;
    // initialize entry frame
    cur_frame->func     = func;
    cur_frame->base     = sp;
    cur_frame->ret_addr = NULL;

    struct hg_ins* pc = cur_frame->func->code;

#define vdispatch(code) switch (code->op)
#define vcase(x, y) \
    case x:         \
        y;          \
        break;
#define vdefault(y) \
    default:        \
        y

#ifdef HG_VM_JUMPTABLE
#include "vm_jumptable.h"
#endif // HG_VM_JUMPTABLE

    while (true) {
        vdispatch(pc) {
            vcase(HG_OP_ADD, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i + sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_SUB, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i - sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_MUL, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i * sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_DIV, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i / sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_MOD, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i % sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_AND, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i && sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_OR, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i || sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_GT, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i > sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_LT, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i < sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_EQ, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i == sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_NEQ, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;
                int32_t rb = pc->as.ari.rb;

                sp[rt].as.i = sp[ra].as.i != sp[rb].as.i;
                pc++;
            });
            vcase(HG_OP_NOT, {
                int32_t rt = pc->as.ari.rt;
                int32_t ra = pc->as.ari.ra;

                sp[rt].as.i = !(sp[ra].as.i);
                pc++;
            });
            vcase(HG_OP_JUMPFALSE, {
                int32_t rx    = pc->as.jump.rx;
                int32_t label = pc->as.jump.label;
                if (sp[rx].as.i) {
                    pc += label;
                } else {
                    pc++;
                }
            });
            vcase(HG_OP_JUMP, {
                int32_t label = pc->as.jump.label;
                pc += label;
            });
            vcase(HG_OP_CALL, {
                int32_t rx = pc->as.call.rx;
                int32_t n  = pc->as.call.n;
                int32_t m  = pc->as.call.m;

                struct hg_function* fn = sp[rx].as.func;
                assert((size_t)n == fn->num_args);
                assert((size_t)m == fn->num_returns);

                //  push frame; TODO: check frame size
                struct hg_call_frame* new_frame = cur_frame + 1;

                new_frame->func     = fn;
                new_frame->ret_addr = pc + 1;
                new_frame->base     = sp + rx; // TODO: check stack size

                cur_frame = new_frame;

                sp = new_frame->base;
                pc = fn->code;
            });
            vcase(HG_OP_RETURN, {
                pc = cur_frame->ret_addr;
                cur_frame--;
                if (cur_frame->ret_addr == NULL) {
                    // entry function
                    return sp[0];
                }
            });
            vcase(HG_OP_MOVE, {
                int32_t rx = pc->as.move.rx;
                int32_t rt = pc->as.move.rt;
                sp[rt]     = sp[rx];
                pc++;
            });
            vcase(HG_OP_LOADC, {
                int32_t rx = pc->as.load.rx;
                int32_t n  = pc->as.load.n;
                sp[rx]     = cur_frame->func->constants[n];
                pc++;
            });
            vdefault({ unreachable_(); });
        }
    }
    return (struct hg_value){.as.i = 0};
#undef vdispatch
#undef vcase
#undef vdefault
}

// Assembly:
pushq %rbx
subq $0x400, %rsp            # imm = 0x400
movq 0x8(%rdi), %rcx
movq 0x18(%rdi), %rdi
movq %rsi, (%rdi)
movq %rcx, 0x10(%rdi)
movq $0x0, 0x8(%rdi)
movq 0x28(%rsi), %r8
leaq 0x21fa(%rip), %rsi      # 0x35f0
movzbl (%r8), %eax
jmpq *(%rsi,%rax,8)
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%r9,8), %r9
addq (%rcx,%rdx,8), %r9
jmp 0x152e
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq %al, %rax
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
jmp 0x1637
movzwl 0x1(%r8), %eax
movswl %ax, %r9d
shrl $0x8, %r9d
movsbq %al, %rdx
movq (%rcx,%rdx,8), %rax
movswq %r9w, %r9
cmpq %r9, (%rax)
jne 0x16ea
movsbq 0x3(%r8), %r9
cmpq %r9, 0x8(%rax)
jne 0x1709
leaq (%rcx,%rdx,8), %rcx
movq %rax, 0x18(%rdi)
addq $0x4, %r8
movq %r8, 0x20(%rdi)
movq %rcx, 0x28(%rdi)
addq $0x18, %rdi
movq 0x28(%rax), %r8
jmp 0x13f6
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movswq %dx, %rdx
xorl %r9d, %r9d
cmpq $0x0, (%rcx,%rdx,8)
sete %r9b
jmp 0x152e
movzwl 0x1(%r8), %r9d
movswl %r9w, %eax
shrl $0x8, %eax
movsbq 0x3(%r8), %r10
movswq %ax, %rax
movq (%rcx,%rax,8), %rax
cqto
idivq (%rcx,%r10,8)
movsbq %r9b, %rax
jmp 0x1637
movsbq 0x1(%r8), %rax
cmpq $0x0, (%rcx,%rax,8)
jne 0x15f9
jmp 0x168d
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r10d, %r10d
cmpq (%rcx,%r9,8), %rdx
sete %r10b
jmp 0x1685
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%r9,8), %r9
imulq (%rcx,%rdx,8), %r9
movsbq %al, %rax
movq %r9, (%rcx,%rax,8)
jmp 0x168d
cmpq $0x0, -0x10(%rdi)
je 0x1696
movq 0x8(%rdi), %r8
addq $-0x18, %rdi
jmp 0x13f6
movzwl 0x1(%r8), %r9d
movswl %r9w, %eax
shrl $0x8, %eax
movsbq 0x3(%r8), %r10
movswq %ax, %rax
movq (%rcx,%rax,8), %rax
cqto
idivq (%rcx,%r10,8)
movsbq %r9b, %rdx
movq %rax, (%rcx,%rdx,8)
jmp 0x168d
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r10d, %r10d
cmpq (%rcx,%r9,8), %rdx
setg %r10b
jmp 0x1685
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
subq (%rcx,%r9,8), %rdx
movsbq %al, %rax
jmp 0x1637
movsbq 0x1(%r8), %rax
movswq 0x2(%r8), %rdx
movq (%rdi), %r9
movq 0x18(%r9), %r9
movq (%r9,%rdx,8), %rdx
jmp 0x1637
movswl 0x1(%r8), %eax
movl %eax, %edx
shrl $0x8, %edx
movswq %dx, %rdx
cmpq $0x0, (%rcx,%rdx,8)
jne 0x1621
xorl %edx, %edx
jmp 0x1630
movswq 0x2(%r8), %rax
leaq (%r8,%rax,4), %r8
jmp 0x13f6
movswl 0x1(%r8), %eax
movl %eax, %edx
shrl $0x8, %edx
movswq %dx, %r9
movl $0x1, %edx
cmpq $0x0, (%rcx,%r9,8)
jne 0x1630
movsbq 0x3(%r8), %r9
xorl %edx, %edx
cmpq $0x0, (%rcx,%r9,8)
setne %dl
movsbl %al, %eax
movswq %ax, %rax
movq %rdx, (%rcx,%rax,8)
jmp 0x168d
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r10d, %r10d
cmpq (%rcx,%r9,8), %rdx
setne %r10b
jmp 0x1685
movzwl 0x1(%r8), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r8), %r9
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r10d, %r10d
cmpq (%rcx,%r9,8), %rdx
setl %r10b
movsbq %al, %rax
movq %r10, (%rcx,%rax,8)
addq $0x4, %r8
jmp 0x13f6
movq (%rcx), %rax
addq $0x400, %rsp            # imm = 0x400
popq %rbx
retq
movq 0x2947(%rip), %rax      # 0x3ff0
movq (%rax), %rdi
leaq 0x9da(%rip), %rsi       # 0x208d
leaq 0x9ef(%rip), %rdx       # 0x20a9
xorl %eax, %eax
callq 0x10a0
movq %rsp, %rbx
movq %rbx, %rdi
movl $0x80, %esi
callq 0x1070
movq %rbx, %rdi
movl %eax, %esi
movl $0x2, %edx
callq 0x1050
movl $0xffffffff, %edi       # imm = 0xFFFFFFFF
callq 0x10d0
leaq 0x913(%rip), %rdi       # 0x2004
leaq 0x926(%rip), %rsi       # 0x201e
leaq 0x927(%rip), %rcx       # 0x2026
movl $0x8f, %edx
callq 0x1090
leaq 0x960(%rip), %rdi       # 0x2070
leaq 0x907(%rip), %rsi       # 0x201e
leaq 0x908(%rip), %rcx       # 0x2026
movl $0x90, %edx
callq 0x1090