// File: /workspace/github_c_makefile_star2_O2/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)
andq $0x0, 0x8(%rdi)
movq 0x28(%rsi), %r9
leaq 0x23ed(%rip), %rsi      # 0x35f0
pushq $0x1
popq %r8
movzbl (%r9), %eax
jmpq *(%rsi,%rax,8)
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%r10,8), %r10
addq (%rcx,%rdx,8), %r10
jmp 0x133f
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq %al, %rax
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
jmp 0x1446
movzwl 0x1(%r9), %eax
movswl %ax, %r10d
shrl $0x8, %r10d
movsbq %al, %rdx
movq (%rcx,%rdx,8), %rax
movswq %r10w, %r10
cmpq %r10, (%rax)
jne 0x14f5
movsbq 0x3(%r9), %r10
cmpq %r10, 0x8(%rax)
jne 0x1514
leaq (%rcx,%rdx,8), %rcx
movq %rax, 0x18(%rdi)
addq $0x4, %r9
movq %r9, 0x20(%rdi)
movq %rcx, 0x28(%rdi)
addq $0x18, %rdi
movq 0x28(%rax), %r9
jmp 0x1207
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movswq %dx, %rdx
xorl %r10d, %r10d
cmpq $0x0, (%rcx,%rdx,8)
sete %r10b
jmp 0x133f
movzwl 0x1(%r9), %r10d
movswl %r10w, %eax
shrl $0x8, %eax
movsbq 0x3(%r9), %r11
movswq %ax, %rax
movq (%rcx,%rax,8), %rax
cqto
idivq (%rcx,%r11,8)
movsbq %r10b, %rax
jmp 0x1446
movsbq 0x1(%r9), %rax
cmpq $0x0, (%rcx,%rax,8)
jne 0x140a
jmp 0x149c
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r11d, %r11d
cmpq (%rcx,%r10,8), %rdx
sete %r11b
jmp 0x1494
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%r10,8), %r10
imulq (%rcx,%rdx,8), %r10
movsbq %al, %rax
movq %r10, (%rcx,%rax,8)
jmp 0x149c
cmpq $0x0, -0x10(%rdi)
je 0x14a5
movq 0x8(%rdi), %r9
addq $-0x18, %rdi
jmp 0x1207
movzwl 0x1(%r9), %r10d
movswl %r10w, %eax
shrl $0x8, %eax
movsbq 0x3(%r9), %r11
movswq %ax, %rax
movq (%rcx,%rax,8), %rax
cqto
idivq (%rcx,%r11,8)
movsbq %r10b, %rdx
movq %rax, (%rcx,%rdx,8)
jmp 0x149c
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r11d, %r11d
cmpq (%rcx,%r10,8), %rdx
setg %r11b
jmp 0x1494
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
subq (%rcx,%r10,8), %rdx
movsbq %al, %rax
jmp 0x1446
movsbq 0x1(%r9), %rax
movswq 0x2(%r9), %rdx
movq (%rdi), %r10
movq 0x18(%r10), %r10
movq (%r10,%rdx,8), %rdx
jmp 0x1446
movswl 0x1(%r9), %eax
movl %eax, %edx
shrl $0x8, %edx
movswq %dx, %rdx
cmpq $0x0, (%rcx,%rdx,8)
jne 0x1430
xorl %edx, %edx
jmp 0x143f
movswq 0x2(%r9), %rax
leaq (%r9,%rax,4), %r9
jmp 0x1207
movswl 0x1(%r9), %eax
movl %eax, %edx
shrl $0x8, %edx
movswq %dx, %rdx
cmpq $0x0, (%rcx,%rdx,8)
movq %r8, %rdx
jne 0x143f
movsbq 0x3(%r9), %r10
xorl %edx, %edx
cmpq $0x0, (%rcx,%r10,8)
setne %dl
movsbl %al, %eax
movswq %ax, %rax
movq %rdx, (%rcx,%rax,8)
jmp 0x149c
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r11d, %r11d
cmpq (%rcx,%r10,8), %rdx
setne %r11b
jmp 0x1494
movzwl 0x1(%r9), %eax
movswl %ax, %edx
shrl $0x8, %edx
movsbq 0x3(%r9), %r10
movswq %dx, %rdx
movq (%rcx,%rdx,8), %rdx
xorl %r11d, %r11d
cmpq (%rcx,%r10,8), %rdx
setl %r11b
movsbq %al, %rax
movq %r11, (%rcx,%rax,8)
addq $0x4, %r9
jmp 0x1207
movq (%rcx), %rax
addq $0x400, %rsp            # imm = 0x400
popq %rbx
retq
movq 0x2b38(%rip), %rax      # 0x3ff0
movq (%rax), %rdi
leaq 0xbcb(%rip), %rsi       # 0x208d
leaq 0xbe0(%rip), %rdx       # 0x20a9
xorl %eax, %eax
callq 0x10a0
movq %rsp, %rbx
movq %rbx, %rdi
movl $0x80, %esi
callq 0x1070
pushq $0x2
popq %rdx
movq %rbx, %rdi
movl %eax, %esi
callq 0x1050
pushq $-0x1
popq %rdi
callq 0x10d0
leaq 0xb08(%rip), %rdi       # 0x2004
leaq 0xb1b(%rip), %rsi       # 0x201e
leaq 0xb1c(%rip), %rcx       # 0x2026
movl $0x8f, %edx
callq 0x1090
leaq 0xb55(%rip), %rdi       # 0x2070
leaq 0xafc(%rip), %rsi       # 0x201e
leaq 0xafd(%rip), %rcx       # 0x2026
movl $0x90, %edx
callq 0x1090
nop