// File: baziotis[P]minijava-cpp/typecheck.cpp
// Function: MainTypeCheckVisitor::visit(WhileStatement*)
void MainTypeCheckVisitor::visit(WhileStatement *while_stmt) {
    LOG_SCOPE;
    debug_print("MainTypeCheck::WhileStatement\n");
    Type *cond = while_stmt->cond->accept(this);
    poison_stmt(cond);
    llvalue_t cond_val = __expr_context.llval;
    if (cond != this->type_table.bool_type) {
        typecheck_error(while_stmt->loc, "In while statement, the ",
                        "condition expression must have `boolean` type but has: `",
                        cond->name(), "`");
    }

    if (cond_val.kind == LLVALUE::CONST && cond_val.val == 0) {
        // Elide while body because of constant false condition.
        // Assume that the user does not even wants to typecheck it.
        return;
    }
    
    /// Codegen ///

    // Codegen loops as:
    /*
    predecessor:
        cond test code (branch to loop start or after_loop)
    loop_start:
        loop_body
        cond test code (again, branch to loop_start or after_loop)
    after_loop:

    That way, when we're in loop_body, we know whether we came from predecessor
    or from loop_start.
    Note: Here we have already generated the initial cond code when we
    typechecked it.
    */
    
    const char *pred_lbl_str = (while_stmt->pred_lbl == NULL) ?
                                __expr_context.curr_lbl.lbl : while_stmt->pred_lbl;
    while_stmt->pred_lbl = pred_lbl_str;
    llvm_label_t pred_lbl = {pred_lbl_str};
    llvm_label_t loop_lbl, after_loop_lbl;
    long lbl = gen_lbl();
    loop_lbl.construct("while", lbl);
    after_loop_lbl.construct("while_end", lbl);
    
    // Note: We have already tested if the `cond_val` is const with
    // false value. If we reach here and we have a const, then it's
    // definitely true in which case we don't generate the branch, we
    // just get to the loop.
    // However, note that we have to remember that for the while
    // so that we remember if we need to create a phi or not.
    bool generated_cond_branch = false;
    if (cond_val.kind != LLVALUE::CONST) {
        generated_cond_branch = true;
        llvm_branch_cond(cond_val, loop_lbl, after_loop_lbl);
    } else {
        llvm_branch(loop_lbl);
    }
    llvm_gen_lbl(loop_lbl);

    // There are 3 cases for a local inside a loop:
    // 1) No assignment to the local.
    // 2) We have at least one assignment and we have a use _after_ the _first_ assignment.
    // 3) We have at least one assignment and we have a use _before_ the _first_ assignment.

    // We want to insert a phi node for locals in case 3. To do that, we use the `track_buf`.
    // This keeps an `assigned` and `used` for every local. We then "visit" the whole
    // loop body and condition to track in what case we are. To do that, we use
    // an ordering in `assigned` and `used`. After finishing, either they're both
    // 0, or one is bigger than the other denoting the order.

    SerializedHashTable<Local*> locals = __expr_context.method->locals;
    FuncArr<WhileAssign> track_buf = get_track_buf(locals);

    // Track first the body and then the cond,
    // as the condition will be put on the bottom.
    track_while_assignment_for_stmt(while_stmt->body, track_buf);
    track_while_assignment_for_expr(while_stmt->cond, track_buf);

    /* -- Main algorithm for insert phi nodes --

    Assuming that we have an ordering now, we need to handle case 3) (from above)
    locals. For those we will insert a phi node at the start of the loop
    that decides between the previous value (the value before the loop) and
    the value inside the loop. Let's note some problems:
    1) We have to know the value inside the loop _before_ we actually generate
       the loop. This is kind of impossible so there are 2 ways:
       a) Generate the loop (say into a buffer), then read this IR, find the values
          and then regenerate the loop with the suitable phi nodes on the start.
       b) Generate the loop (but by disabling actual codegen, i.e. printing), find
          the values, generate the phi nodes and then regenerate the loop as it was
          never generated.
       We will do b) as it is of course way easier and faster. But that comes later.
       Before that we have to solve another problem:
    2) To do the first fake generation that was described 1b) above, we have to know
       the register that was assigned to the phi node, _before_ we can generate
       the phi node.
    
    To see both 1) and 2) into action, consider this:
        
       ```
       a = 3;
       while (a < 4) {
          a = a + 1;
       }
       ```
        
       That has to generate something like this:
       ```
           // ... (`a` has gotten constant value 3 here)
       while1:
           %1 = phi i32 [ 3, entry ], [ %2, while1 ]
           %2 = add i32 %1, 1
           %3 = icmp slt i32 %2, 4
           br i1 %3, label while1, label while_end1
       
       while_end1:
           // ...
       ```

       Note that to generate the phi node in %1, we have to know that `a`
       gets the llvalue %2. But, we can't know that _before_ we generate the body.
       So, let's say that we go to generate it. Well, to generate it, when we
       go to generate code for %2, we have to know that `a` has the llvalue %1.
       If we _don't_ somehow do that and do the generation normally, then when we
       generate code for %2, the value that will be assigned to `a` will be the
       constant value 3. And that's of course wrong code generation.

       To solve that we decide the register in which we will save the phi node
       before we actually. Because of the ordering (which remember, comes before all that),
       we know e.g. that we have to generate a phi node for `a`. At this point we can't
       generate the phi node, but we can decide that its value will be saved e.g. in %1.
       Then, we save the llvalue of `a` to be %1 (e.g. local->llval = ...). In that way,
       when we do the first fake generation of, when we go to generate %2, it uses %1
       as the llvalue of `a`. Then of course `a` gets as llvalue the %2.
       And _now_, after finishing the fake generation, we know that `a` got assigned
       as llvalue the %2. And so, we generate the phi node between the constant value
       3 (the previous value i.e. that before the loop) and %2 (the new value).

       Ok, to do all that we need 2 buffers:
       1) `previous_values` holds the values of the locals _before_ the loop.
       2) `new_assigned_values` holds the values that we assign a priori to the phi
          nodes that _will_ be generated.
    */

    FuncArr<llvalue_t> previous_values, new_assigned_values;
    previous_values.reserve(locals.len);
    new_assigned_values.reserve(locals.len);
    // Initialize the 2 buffers.
    for (Local *local : locals) {
        previous_values.push(local->llval);
        // DUMB VALUE
        new_assigned_values.push(const_llv(0, {}));
    }

    /// Decide for which locals we have to make a phi node
    /// and get a register for the phi node (that will be generated later).
    size_t i = 0;
    for (WhileAssign wa : track_buf) {
        assert(i < locals.len);
        // Either no use and no assignment or they are not equal (since
        // we should have ordering).
        assert((!wa.assigned && !wa.used) || (wa.used != wa.assigned));
        if (wa.assigned && wa.used && wa.used < wa.assigned) {
            Local *local = locals[i];
            new_assigned_values[i].kind = LLVALUE::REG;
            new_assigned_values[i].reg = gen_reg();
            local->llval = new_assigned_values[i];
        }
        ++i;
    }

    /// Do the fake generation (by disabling codegen).
    /// That requires some boilterplate to save and restore the state of registers
    /// and labels.

    assert(while_stmt->body);
    bool save_codegen = config.codegen;
    // TODO: We should have a save state / restore state.
    // Get the last register but we actually have to reset it immediately.
    long save_reg = gen_reg();
    set_reg(save_reg);
    long save_lbl = gen_lbl();
    set_lbl(save_lbl);
    config.codegen = false;
    while_stmt->body->accept(this);
    while_stmt->cond->accept(this);
    const char *last_lbl_str = (while_stmt->last_lbl == NULL) ?
                                __expr_context.curr_lbl.lbl : while_stmt->last_lbl;
    while_stmt->last_lbl = last_lbl_str;
    llvm_label_t last_lbl = {last_lbl_str};
    set_reg(save_reg);
    set_lbl(save_lbl);
    config.codegen = save_codegen;

    
    /// Now that we know the llvalue that the locals got in the loop,
    /// generate the phi nodes. Note that they're locals that might have been
    /// assigned but either never used or used after the assignment. In these
    /// cases we don't want to insert a phi node but we do want to restore their
    /// llvalue so that the actual code generation is correct.
    i = 0;
    for (WhileAssign wa : track_buf) {
        Local *local = wa.local;
        if (wa.assigned && wa.used && wa.used < wa.assigned) {
            long reg = new_assigned_values[i].reg;
            local->llval = while_phi_node(local->type, previous_values[i], local->llval,
                                          pred_lbl, last_lbl, reg);
        } else if (wa.assigned) {
            // Restore in the general case
            local->llval = previous_values[i];
        }
        ++i;
    }
    
    /// Do the actual code generation (note that we generate the cond on the
    /// bottom etc. - as described above on how while loops are generated / transformed).
    while_stmt->body->accept(this);
    while_stmt->cond->accept(this);
    cond_val = __expr_context.llval;
    llvm_branch_cond(cond_val, loop_lbl, after_loop_lbl);
    llvm_gen_lbl(after_loop_lbl);
    
    /// Last but not least, we want to generate a phi nodes for all
    /// the locals that were assigned inside the loop (regardless of the usage).
    /// Of course the phi will be between their before-loop-llvalue and the
    /// value they get assigned inside the loop.

    // Generate a phi node after the while. Do that only if the condition
    // was not known and so a conditional branch was inserted.
    if (generated_cond_branch) {
      i = 0;
      for (WhileAssign wa : track_buf) {
          Local *local = wa.local;
          llvalue_t prev_value = previous_values[i];
          llvalue_t new_value = local->llval;
          if (wa.assigned) {
              local->llval = llvm_phi_node(local->type, prev_value, new_value,
                                           pred_lbl, last_lbl);
          }
          ++i;
      }
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x590, %rsp            # imm = 0x590
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x478(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x3da0
leaq 0x8aa1(%rip), %rdi      # 0x1c85f
xorl %eax, %eax
callq 0x3e60
jmp 0x13dc7
movq -0x478(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x16490
movq %rax, -0x480(%rbp)
jmp 0x13de4
movq -0x480(%rbp), %rax
movq %rax, -0x30(%rbp)
movq -0x30(%rbp), %rax
cmpl $0x0, 0x4(%rax)
jne 0x13e1f
movl $0x1, -0x34(%rbp)
jmp 0x14c2d
movq %rax, %rcx
movl %edx, %eax
movq %rcx, -0x20(%rbp)
movl %eax, -0x24(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x3dd0
jmp 0x14c3f
movq -0x478(%rbp), %rcx
leaq 0x10b9b(%rip), %rax     # 0x249c8
movq 0x8(%rax), %rdx
movq %rdx, -0x60(%rbp)
movq 0x10(%rax), %rdx
movq %rdx, -0x58(%rbp)
movq 0x18(%rax), %rdx
movq %rdx, -0x50(%rbp)
movq 0x20(%rax), %rax
movq %rax, -0x48(%rbp)
movq -0x30(%rbp), %rax
cmpq 0x8(%rcx), %rax
je 0x13e9b
movq -0x10(%rbp), %rax
movl 0xc(%rax), %eax
movl %eax, -0x64(%rbp)
movq -0x30(%rbp), %rdi
callq 0xc180
movq %rax, -0x488(%rbp)
jmp 0x13e73
movq -0x488(%rbp), %rcx
movl -0x64(%rbp), %edi
leaq 0x89fa(%rip), %rsi      # 0x1c87e
leaq 0x88e0(%rip), %rdx      # 0x1c76b
leaq 0x6e9b(%rip), %r8       # 0x1ad2d
callq 0xcca0
jmp 0x13e99
jmp 0x13e9b
cmpl $0x1, -0x60(%rbp)
jne 0x13eb3
cmpl $0x0, -0x48(%rbp)
jne 0x13eb3
movl $0x1, -0x34(%rbp)
jmp 0x14c2d
movq -0x10(%rbp), %rax
cmpq $0x0, 0x20(%rax)
jne 0x13ed1
leaq 0x10b03(%rip), %rax     # 0x249c8
movq (%rax), %rax
movq %rax, -0x490(%rbp)
jmp 0x13ee0
movq -0x10(%rbp), %rax
movq 0x20(%rax), %rax
movq %rax, -0x490(%rbp)
movq -0x490(%rbp), %rax
movq %rax, -0x70(%rbp)
movq -0x70(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x70(%rbp), %rsi
leaq -0x78(%rbp), %rdi
callq 0x7990
jmp 0x13f06
leaq -0x80(%rbp), %rdi
callq 0x79b0
jmp 0x13f11
leaq -0x88(%rbp), %rdi
callq 0x79b0
jmp 0x13f1f
callq 0x5ab0
movq %rax, -0x498(%rbp)
jmp 0x13f2d
movq -0x498(%rbp), %rax
movq %rax, -0x90(%rbp)
movq -0x90(%rbp), %rdx
leaq 0x76ee(%rip), %rsi      # 0x1b637
leaq -0x80(%rbp), %rdi
callq 0x167d0
jmp 0x13f54
movq -0x90(%rbp), %rdx
leaq 0x8935(%rip), %rsi      # 0x1c897
leaq -0x88(%rbp), %rdi
callq 0x167d0
jmp 0x13f70
movb $0x0, -0x91(%rbp)
cmpl $0x1, -0x60(%rbp)
je 0x13fe2
movb $0x1, -0x91(%rbp)
movups -0x60(%rbp), %xmm0
movups -0x50(%rbp), %xmm1
movaps %xmm1, -0xb0(%rbp)
movaps %xmm0, -0xc0(%rbp)
movq -0x80(%rbp), %rax
movq %rax, -0xc8(%rbp)
movq -0x88(%rbp), %rax
movq %rax, -0xd0(%rbp)
movq -0xc8(%rbp), %rdi
movq -0xd0(%rbp), %rsi
movaps -0xc0(%rbp), %xmm0
movaps -0xb0(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
callq 0x6c50
jmp 0x13fe0
jmp 0x13ffd
movq -0x80(%rbp), %rax
movq %rax, -0xd8(%rbp)
movq -0xd8(%rbp), %rdi
callq 0x6cf0
jmp 0x13ffb
jmp 0x13ffd
movq -0x80(%rbp), %rax
movq %rax, -0xe0(%rbp)
movq -0xe0(%rbp), %rdi
callq 0x6c20
jmp 0x14016
leaq 0x109ab(%rip), %rax     # 0x249c8
movq 0x28(%rax), %rax
movups 0x18(%rax), %xmm0
movups 0x28(%rax), %xmm1
movups 0x38(%rax), %xmm2
movaps %xmm2, -0xf0(%rbp)
movaps %xmm1, -0x100(%rbp)
movaps %xmm0, -0x110(%rbp)
movaps -0x110(%rbp), %xmm0
movaps -0x100(%rbp), %xmm1
movaps -0xf0(%rbp), %xmm2
movaps %xmm2, -0x140(%rbp)
movaps %xmm1, -0x150(%rbp)
movaps %xmm0, -0x160(%rbp)
movaps -0x160(%rbp), %xmm0
movaps -0x150(%rbp), %xmm1
movaps -0x140(%rbp), %xmm2
movq %rsp, %rax
movups %xmm2, 0x20(%rax)
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x128(%rbp), %rdi
callq 0x13cd0
jmp 0x1409d
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
movq -0x118(%rbp), %rax
movq %rax, -0x170(%rbp)
movups -0x128(%rbp), %xmm0
movaps %xmm0, -0x180(%rbp)
movq -0x170(%rbp), %rcx
movq %rsp, %rax
movq %rcx, 0x10(%rax)
movaps -0x180(%rbp), %xmm0
movups %xmm0, (%rax)
callq 0x135c0
jmp 0x140e0
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
movq -0x118(%rbp), %rax
movq %rax, -0x190(%rbp)
movups -0x128(%rbp), %xmm0
movaps %xmm0, -0x1a0(%rbp)
movq -0x190(%rbp), %rcx
movq %rsp, %rax
movq %rcx, 0x10(%rax)
movaps -0x1a0(%rbp), %xmm0
movups %xmm0, (%rax)
callq 0x13290
jmp 0x14123
leaq -0x1b8(%rbp), %rdi
callq 0x16b10
jmp 0x14131
leaq -0x1d0(%rbp), %rdi
callq 0x16b10
jmp 0x1413f
movq -0xf0(%rbp), %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x16b40
jmp 0x14154
movq -0xf0(%rbp), %rsi
leaq -0x1d0(%rbp), %rdi
callq 0x16b40
jmp 0x14169
leaq -0x110(%rbp), %rax
movq %rax, -0x1d8(%rbp)
movq -0x1d8(%rbp), %rdi
callq 0x15780
movq %rax, -0x4a0(%rbp)
jmp 0x1418c
movq -0x4a0(%rbp), %rax
movq %rax, -0x1e0(%rbp)
movq -0x1d8(%rbp), %rdi
callq 0x157a0
movq %rax, -0x4a8(%rbp)
jmp 0x141af
movq -0x4a8(%rbp), %rax
movq %rax, -0x1e8(%rbp)
movq -0x1e0(%rbp), %rax
cmpq -0x1e8(%rbp), %rax
je 0x14296
movq -0x1e0(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x1f0(%rbp)
movq -0x1f0(%rbp), %rax
movups 0x10(%rax), %xmm0
movups 0x20(%rax), %xmm1
movaps %xmm1, -0x200(%rbp)
movaps %xmm0, -0x210(%rbp)
movaps -0x210(%rbp), %xmm0
movaps -0x200(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x1b8(%rbp), %rdi
callq 0x16630
jmp 0x14225
movq $0x0, -0x240(%rbp)
movl $0x0, -0x238(%rbp)
movq -0x240(%rbp), %rdx
movl -0x238(%rbp), %ecx
leaq -0x230(%rbp), %rdi
xorl %esi, %esi
callq 0x5b20
jmp 0x14257
movups -0x230(%rbp), %xmm0
movups -0x220(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x1d0(%rbp), %rdi
callq 0x16630
jmp 0x1427d
jmp 0x1427f
movq -0x1e0(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x1e0(%rbp)
jmp 0x141bd
movq $0x0, -0x248(%rbp)
leaq -0x128(%rbp), %rax
movq %rax, -0x250(%rbp)
movq -0x250(%rbp), %rdi
callq 0x169e0
movq %rax, -0x4b0(%rbp)
jmp 0x142c4
movq -0x4b0(%rbp), %rax
movq %rax, -0x258(%rbp)
movq -0x250(%rbp), %rdi
callq 0x16a00
movq %rax, -0x4b8(%rbp)
jmp 0x142e7
movq -0x4b8(%rbp), %rax
movq %rax, -0x260(%rbp)
movq -0x258(%rbp), %rax
cmpq -0x260(%rbp), %rax
je 0x14524
movq -0x258(%rbp), %rax
movq (%rax), %rcx
movq %rcx, -0x270(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0x268(%rbp)
movq -0x248(%rbp), %rax
cmpq -0xf0(%rbp), %rax
jae 0x14337
jmp 0x14356
leaq 0x8563(%rip), %rdi      # 0x1c8a1
leaq 0x7419(%rip), %rsi      # 0x1b75e
movl $0x88a, %edx            # imm = 0x88A
leaq 0x855f(%rip), %rcx      # 0x1c8b0
callq 0x20d0
movb -0x268(%rbp), %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
jne 0x14381
movb -0x268(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %ecx
movb $0x1, %al
cmpl $0x0, %ecx
movb %al, -0x4b9(%rbp)
je 0x143a6
movb -0x268(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %eax
movb -0x268(%rbp), %cl
andb $0x3, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
setne %al
movb %al, -0x4b9(%rbp)
movb -0x4b9(%rbp), %al
testb $0x1, %al
jne 0x143b2
jmp 0x143b4
jmp 0x143d3
leaq 0x8528(%rip), %rdi      # 0x1c8e3
leaq 0x739c(%rip), %rsi      # 0x1b75e
movl $0x88d, %edx            # imm = 0x88D
leaq 0x84e2(%rip), %rcx      # 0x1c8b0
callq 0x20d0
movb -0x268(%rbp), %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x144fb
movb -0x268(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x144fb
movb -0x268(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %eax
movb -0x268(%rbp), %cl
andb $0x3, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
jge 0x144fb
movq -0x248(%rbp), %rsi
leaq -0x110(%rbp), %rdi
callq 0x7870
movq %rax, -0x4c8(%rbp)
jmp 0x1443c
movq -0x4c8(%rbp), %rax
movq (%rax), %rax
movq %rax, -0x278(%rbp)
movq -0x248(%rbp), %rsi
leaq -0x1d0(%rbp), %rdi
callq 0x7900
movq %rax, -0x4d0(%rbp)
jmp 0x14469
movq -0x4d0(%rbp), %rax
movl $0x2, (%rax)
callq 0x5a40
movq %rax, -0x4d8(%rbp)
jmp 0x14484
movq -0x248(%rbp), %rsi
leaq -0x1d0(%rbp), %rdi
callq 0x7900
movq %rax, -0x4e0(%rbp)
jmp 0x144a0
movq -0x4e0(%rbp), %rax
movq -0x4d8(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq -0x248(%rbp), %rsi
leaq -0x1d0(%rbp), %rdi
callq 0x7900
movq %rax, -0x4e8(%rbp)
jmp 0x144ce
movq -0x4e8(%rbp), %rcx
movq -0x278(%rbp), %rax
movq (%rcx), %rdx
movq %rdx, 0x10(%rax)
movq 0x8(%rcx), %rdx
movq %rdx, 0x18(%rax)
movq 0x10(%rcx), %rdx
movq %rdx, 0x20(%rax)
movq 0x18(%rcx), %rcx
movq %rcx, 0x28(%rax)
movq -0x248(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x248(%rbp)
movq -0x258(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x258(%rbp)
jmp 0x142f5
movq -0x10(%rbp), %rax
cmpq $0x0, 0x18(%rax)
je 0x14531
jmp 0x14550
leaq 0x83e2(%rip), %rdi      # 0x1c91a
leaq 0x721f(%rip), %rsi      # 0x1b75e
movl $0x89b, %edx            # imm = 0x89B
leaq 0x8365(%rip), %rcx      # 0x1c8b0
callq 0x20d0
leaq 0x104f1(%rip), %rax     # 0x24a48
movb 0x4(%rax), %al
andb $0x1, %al
movb %al, -0x279(%rbp)
callq 0x5a40
movq %rax, -0x4f0(%rbp)
jmp 0x14570
movq -0x4f0(%rbp), %rax
movq %rax, -0x288(%rbp)
movq -0x288(%rbp), %rdi
callq 0x5a20
jmp 0x1458c
callq 0x5ab0
movq %rax, -0x4f8(%rbp)
jmp 0x1459a
movq -0x4f8(%rbp), %rax
movq %rax, -0x290(%rbp)
movq -0x290(%rbp), %rdi
callq 0x5a90
jmp 0x145b6
movq -0x478(%rbp), %rsi
leaq 0x10484(%rip), %rax     # 0x24a48
movb $0x0, 0x4(%rax)
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
movq (%rdi), %rax
movq 0x18(%rax), %rax
callq *%rax
jmp 0x145db
movq -0x478(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x16490
jmp 0x145f1
movq -0x10(%rbp), %rax
cmpq $0x0, 0x28(%rax)
jne 0x1460f
leaq 0x103c5(%rip), %rax     # 0x249c8
movq (%rax), %rax
movq %rax, -0x500(%rbp)
jmp 0x1461e
movq -0x10(%rbp), %rax
movq 0x28(%rax), %rax
movq %rax, -0x500(%rbp)
movq -0x500(%rbp), %rax
movq %rax, -0x298(%rbp)
movq -0x298(%rbp), %rcx
movq -0x10(%rbp), %rax
movq %rcx, 0x28(%rax)
movq -0x298(%rbp), %rsi
leaq -0x2a0(%rbp), %rdi
callq 0x7990
jmp 0x14650
movq -0x288(%rbp), %rdi
callq 0x5a20
jmp 0x1465e
movq -0x290(%rbp), %rdi
callq 0x5a90
jmp 0x1466c
movb -0x279(%rbp), %cl
andb $0x1, %cl
leaq 0x103cc(%rip), %rax     # 0x24a48
movb %cl, 0x4(%rax)
movq $0x0, -0x248(%rbp)
leaq -0x128(%rbp), %rax
movq %rax, -0x2a8(%rbp)
movq -0x2a8(%rbp), %rdi
callq 0x169e0
movq %rax, -0x508(%rbp)
jmp 0x146ad
movq -0x508(%rbp), %rax
movq %rax, -0x2b0(%rbp)
movq -0x2a8(%rbp), %rdi
callq 0x16a00
movq %rax, -0x510(%rbp)
jmp 0x146d0
movq -0x510(%rbp), %rax
movq %rax, -0x2b8(%rbp)
movq -0x2b0(%rbp), %rax
cmpq -0x2b8(%rbp), %rax
je 0x14928
movq -0x2b0(%rbp), %rax
movq (%rax), %rcx
movq %rcx, -0x2c8(%rbp)
movq 0x8(%rax), %rax
movq %rax, -0x2c0(%rbp)
movq -0x2c8(%rbp), %rax
movq %rax, -0x2d0(%rbp)
movb -0x2c0(%rbp), %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x148a4
movb -0x2c0(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x148a4
movb -0x2c0(%rbp), %al
shrb $0x2, %al
andb $0x3, %al
movzbl %al, %eax
movb -0x2c0(%rbp), %cl
andb $0x3, %cl
movzbl %cl, %ecx
cmpl %ecx, %eax
jge 0x148a4
movq -0x248(%rbp), %rsi
leaq -0x1d0(%rbp), %rdi
callq 0x7900
movq %rax, -0x518(%rbp)
jmp 0x14785
movq -0x518(%rbp), %rax
movq 0x18(%rax), %rax
movq %rax, -0x2d8(%rbp)
movq -0x2d0(%rbp), %rax
movq 0x8(%rax), %rax
movq %rax, -0x528(%rbp)
movq -0x248(%rbp), %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x7900
movq %rax, -0x520(%rbp)
jmp 0x147c5
movq -0x528(%rbp), %rsi
movq -0x520(%rbp), %rax
movups (%rax), %xmm0
movups 0x10(%rax), %xmm1
movaps %xmm1, -0x310(%rbp)
movaps %xmm0, -0x320(%rbp)
movq -0x2d0(%rbp), %rax
movups 0x10(%rax), %xmm0
movups 0x20(%rax), %xmm1
movaps %xmm1, -0x330(%rbp)
movaps %xmm0, -0x340(%rbp)
movq -0x78(%rbp), %rax
movq %rax, -0x348(%rbp)
movq -0x2a0(%rbp), %rax
movq %rax, -0x350(%rbp)
movq -0x2d8(%rbp), %r8
movq -0x348(%rbp), %rdx
movq -0x350(%rbp), %rcx
movaps -0x340(%rbp), %xmm0
movaps -0x330(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x30(%rax)
movups %xmm0, 0x20(%rax)
movaps -0x320(%rbp), %xmm0
movaps -0x310(%rbp), %xmm1
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x2f8(%rbp), %rdi
callq 0x13bd0
jmp 0x1486f
movq -0x2d0(%rbp), %rax
movq -0x2f8(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq -0x2f0(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq -0x2e8(%rbp), %rcx
movq %rcx, 0x20(%rax)
movq -0x2e0(%rbp), %rcx
movq %rcx, 0x28(%rax)
jmp 0x148ff
movb -0x2c0(%rbp), %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x148fd
movq -0x248(%rbp), %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x7900
movq %rax, -0x530(%rbp)
jmp 0x148d0
movq -0x530(%rbp), %rcx
movq -0x2d0(%rbp), %rax
movq (%rcx), %rdx
movq %rdx, 0x10(%rax)
movq 0x8(%rcx), %rdx
movq %rdx, 0x18(%rax)
movq 0x10(%rcx), %rdx
movq %rdx, 0x20(%rax)
movq 0x18(%rcx), %rcx
movq %rcx, 0x28(%rax)
jmp 0x148ff
movq -0x248(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x248(%rbp)
movq -0x2b0(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x2b0(%rbp)
jmp 0x146de
movq -0x478(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x18(%rax), %rdi
movq (%rdi), %rax
movq 0x18(%rax), %rax
callq *%rax
jmp 0x14942
movq -0x478(%rbp), %rsi
movq -0x10(%rbp), %rax
movq 0x10(%rax), %rdi
callq 0x16490
jmp 0x14958
leaq 0x10069(%rip), %rax     # 0x249c8
movups 0x8(%rax), %xmm0
movups 0x18(%rax), %xmm1
movaps %xmm1, -0x50(%rbp)
movaps %xmm0, -0x60(%rbp)
movaps -0x60(%rbp), %xmm0
movaps -0x50(%rbp), %xmm1
movaps %xmm1, -0x360(%rbp)
movaps %xmm0, -0x370(%rbp)
movq -0x80(%rbp), %rax
movq %rax, -0x378(%rbp)
movq -0x88(%rbp), %rax
movq %rax, -0x380(%rbp)
movq -0x378(%rbp), %rdi
movq -0x380(%rbp), %rsi
movaps -0x370(%rbp), %xmm0
movaps -0x360(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
callq 0x6c50
jmp 0x149cb
movq -0x88(%rbp), %rax
movq %rax, -0x388(%rbp)
movq -0x388(%rbp), %rdi
callq 0x6c20
jmp 0x149e7
testb $0x1, -0x91(%rbp)
je 0x14c26
movq $0x0, -0x248(%rbp)
leaq -0x128(%rbp), %rax
movq %rax, -0x390(%rbp)
movq -0x390(%rbp), %rdi
callq 0x169e0
movq %rax, -0x538(%rbp)
jmp 0x14a22
movq -0x538(%rbp), %rax
movq %rax, -0x398(%rbp)
movq -0x390(%rbp), %rdi
callq 0x16a00
movq %rax, -0x540(%rbp)
jmp 0x14a45
movq -0x540(%rbp), %rax
movq %rax, -0x3a0(%rbp)
movq -0x398(%rbp), %rax
cmpq -0x3a0(%rbp), %rax
je 0x14c24
movq -0x398(%rbp), %rax
movups (%rax), %xmm0
movaps %xmm0, -0x3b0(%rbp)
movq -0x3b0(%rbp), %rax
movq %rax, -0x3b8(%rbp)
movq -0x248(%rbp), %rsi
leaq -0x1b8(%rbp), %rdi
callq 0x7900
movq %rax, -0x548(%rbp)
jmp 0x14aa2
movq -0x548(%rbp), %rax
movq (%rax), %rcx
movq %rcx, -0x3d8(%rbp)
movq 0x8(%rax), %rcx
movq %rcx, -0x3d0(%rbp)
movq 0x10(%rax), %rcx
movq %rcx, -0x3c8(%rbp)
movq 0x18(%rax), %rax
movq %rax, -0x3c0(%rbp)
movq -0x3b8(%rbp), %rax
movq 0x10(%rax), %rcx
movq %rcx, -0x3f8(%rbp)
movq 0x18(%rax), %rcx
movq %rcx, -0x3f0(%rbp)
movq 0x20(%rax), %rcx
movq %rcx, -0x3e8(%rbp)
movq 0x28(%rax), %rax
movq %rax, -0x3e0(%rbp)
movb -0x3a8(%rbp), %al
andb $0x3, %al
movzbl %al, %eax
cmpl $0x0, %eax
je 0x14bfb
movq -0x3b8(%rbp), %rax
movq 0x8(%rax), %rsi
movups -0x3d8(%rbp), %xmm0
movups -0x3c8(%rbp), %xmm1
movaps %xmm1, -0x430(%rbp)
movaps %xmm0, -0x440(%rbp)
movups -0x3f8(%rbp), %xmm0
movups -0x3e8(%rbp), %xmm1
movaps %xmm1, -0x450(%rbp)
movaps %xmm0, -0x460(%rbp)
movq -0x78(%rbp), %rax
movq %rax, -0x468(%rbp)
movq -0x2a0(%rbp), %rax
movq %rax, -0x470(%rbp)
movq -0x468(%rbp), %rdx
movq -0x470(%rbp), %rcx
movaps -0x460(%rbp), %xmm0
movaps -0x450(%rbp), %xmm1
movq %rsp, %rax
movups %xmm1, 0x30(%rax)
movups %xmm0, 0x20(%rax)
movaps -0x440(%rbp), %xmm0
movaps -0x430(%rbp), %xmm1
movups %xmm1, 0x10(%rax)
movups %xmm0, (%rax)
leaq -0x418(%rbp), %rdi
movq $-0x1, %r8
callq 0x6d20
jmp 0x14bc8
movq -0x3b8(%rbp), %rax
movq -0x418(%rbp), %rcx
movq %rcx, 0x10(%rax)
movq -0x410(%rbp), %rcx
movq %rcx, 0x18(%rax)
movq -0x408(%rbp), %rcx
movq %rcx, 0x20(%rax)
movq -0x400(%rbp), %rcx
movq %rcx, 0x28(%rax)
movq -0x248(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x248(%rbp)
movq -0x398(%rbp), %rax
addq $0x10, %rax
movq %rax, -0x398(%rbp)
jmp 0x14a53
jmp 0x14c26
movl $0x0, -0x34(%rbp)
leaq -0x11(%rbp), %rdi
callq 0x3dd0
addq $0x590, %rsp            # imm = 0x590
popq %rbp
retq
movq -0x20(%rbp), %rdi
callq 0x21c0
nopl (%rax,%rax)