// File: /workspace/github_cpp_makefile_star2_O2/luooofan[P]hblzbd_compiler/src/Pass/arm_offset_fixup.cpp
// Function: SPOffsetFixup::Fixup4Func(ArmFunction*)
void SPOffsetFixup::Fixup4Func(ArmFunction *func) {
#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Prune Instruction Start:" << std::endl;
#endif
  // 每一个函数确定了之后 更改push/pop指令 更改add/sub sp sp stack_size指令
  int offset_fixup_diff = func->used_callee_saved_regs.size() * 4 + func->stack_size_;
  bool is_lr_used = func->used_callee_saved_regs.find(ArmReg::lr) != func->used_callee_saved_regs.end();

#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Modify Push Pop Start:" << std::endl;
#endif
  for (auto bb : func->bb_list_) {
    for (auto iter = bb->inst_list_.begin(); iter != bb->inst_list_.end();) {
      if (auto pushpop_inst = dynamic_cast<PushPop *>(*iter)) {
        // pushpop_inst->EmitCode(outfile);
        pushpop_inst->reg_list_.clear();
        Cond cond = pushpop_inst->cond_;
        for (auto reg : func->used_callee_saved_regs) {
          pushpop_inst->reg_list_.push_back(new Reg(reg));
        }
        if (pushpop_inst->opkind_ == PushPop::OpKind::PUSH) {
          if (pushpop_inst->reg_list_.empty()) {
            iter = bb->inst_list_.erase(iter);
            continue;
          }
        } else {
          if (is_lr_used) {  // 把pop lr 改为pop pc
            MyAssert(pushpop_inst->reg_list_.back()->reg_id_ == ArmReg::lr);
            pushpop_inst->reg_list_.back()->reg_id_ = ArmReg::pc;
          }
          if (pushpop_inst->reg_list_.empty()) {
            iter = bb->inst_list_.erase(iter);
          } else {
            ++iter;
          }
          // 此时iter指向原pop指令的下一条指令
          if (!is_lr_used) {  // 不在push中 插入一条 bx lr
            iter = bb->inst_list_.insert(iter, new Branch(false, true, cond, "lr", bb, false));
          }
          continue;
        }
        ++iter;
      } else {
        ++iter;
      }
    }
  }
#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Modify Push Pop End." << std::endl;
#endif

#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Fixup sp_arg Start:" << std::endl;
#endif

  auto merge_ldrpseudo_with_ldr = [&func](std::unordered_set<Instruction *>::iterator it) {
    // 把ldrpseudo和后面的ldr合起来
    for (auto bb : func->bb_list_) {
      for (auto inst_it = bb->inst_list_.begin(); inst_it != bb->inst_list_.end(); ++inst_it) {
        if (*inst_it == *it) {
          int imm = 0;
          auto src_inst = dynamic_cast<LdrPseudo *>(*inst_it);
          MyAssert(nullptr != src_inst && src_inst->IsImm());
          imm = src_inst->imm_;
          inst_it = bb->inst_list_.erase(inst_it);
          // inst_it现在指向了ldr vreg sp op2指令 要把op2改为立即数类型
          auto ldr_inst = dynamic_cast<LdrStr *>(*inst_it);
          MyAssert(nullptr != ldr_inst && !ldr_inst->is_offset_imm_ && nullptr != ldr_inst->offset_ &&
                   ldr_inst->rn_->reg_id_ == ArmReg::sp && !ldr_inst->offset_->is_imm_ &&
                   ldr_inst->offset_->reg_->reg_id_ == src_inst->rd_->reg_id_);
          // TODO delete src op2
          ldr_inst->offset_ = new Operand2(imm);
          // *it = ldr_inst;  // 之后sp_arg_fixup中会出现ldr指令
          return;
        }
      }
    }
    MyAssert(0);
  };

  // 针对sp_arg的修复 需要修复栈中高处实参的位置 一定是一条ldr-pseudo指令
  for (auto it = func->sp_arg_fixup_.begin(); it != func->sp_arg_fixup_.end(); ++it) {
    auto src_inst = dynamic_cast<LdrPseudo *>(*it);
    MyAssert(nullptr != src_inst && src_inst->IsImm());
    src_inst->imm_ += offset_fixup_diff;
    if (LdrStr::CheckImm12(src_inst->imm_)) {
      merge_ldrpseudo_with_ldr(it);
    }
  }

  func->sp_arg_fixup_.clear();

#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Fixup sp_arg End." << std::endl;
  std::cout << "Fixup sp Start:" << std::endl;
#endif

  auto convert_imm_inst = [&func](std::unordered_set<Instruction *>::iterator it) {
    // 把mov/mvn转换成ldrpseudo
    for (auto bb : func->bb_list_) {
      for (auto inst_it = bb->inst_list_.begin(); inst_it != bb->inst_list_.end(); ++inst_it) {
        if (*inst_it == *it) {
          auto src_inst = dynamic_cast<Move *>(*it);
          MyAssert(nullptr != src_inst && src_inst->op2_->is_imm_);
          inst_it = bb->inst_list_.erase(inst_it);
          int imm = 0;
          if (src_inst->is_mvn_) {
            imm = -src_inst->op2_->imm_num_ - 1;
          } else {
            imm = src_inst->op2_->imm_num_;
          }
          auto pseudo_ldr_inst = new LdrPseudo(Cond::AL, src_inst->rd_, imm, bb);
          inst_it = bb->inst_list_.insert(inst_it, pseudo_ldr_inst);
          // TODO: delete
          // *it = pseudo_ldr_inst;
          return;
        }
      }
    }
    MyAssert(0);
  };

  auto merge_with_addsub = [&func](std::unordered_set<Instruction *>::iterator it) {
    // 把mov/ldrpseudo和后面的addsub sp sp 合起来
    for (auto bb : func->bb_list_) {
      for (auto inst_it = bb->inst_list_.begin(); inst_it != bb->inst_list_.end(); ++inst_it) {
        if (*inst_it == *it) {
          int imm = 0;
          if (auto src_inst = dynamic_cast<Move *>(*it)) {
            MyAssert(src_inst->op2_->is_imm_);
            if (src_inst->is_mvn_) return;
            imm = src_inst->op2_->imm_num_;
          } else if (auto src_inst = dynamic_cast<LdrPseudo *>(*it)) {
            MyAssert(src_inst->IsImm());
            imm = src_inst->imm_;
          } else {
            MyAssert(0);
          }
          inst_it = bb->inst_list_.erase(inst_it);
          // inst_it现在指向了add或sub sp sp op2指令 要把op2改为立即数类型
          auto addsub_inst = dynamic_cast<BinaryInst *>(*inst_it);
          MyAssert(nullptr != addsub_inst && addsub_inst->rd_->reg_id_ == ArmReg::sp &&
                   addsub_inst->rn_->reg_id_ == ArmReg::sp);
          // TODO delete src op2
          addsub_inst->op2_ = new Operand2(imm);
          // *it = addsub_inst;  // 之后sp_fixup中会出现addsub指令
          return;
        }
      }
    }
    MyAssert(0);
  };

  // 针对function prologue和epilogue中sp的修复 原来都是0 可能是mov mvn或者pseudo ldr
  for (auto it = func->sp_fixup_.begin(); it != func->sp_fixup_.end(); ++it) {
    if (auto src_inst = dynamic_cast<Move *>(*it)) {
      MyAssert(src_inst->op2_->is_imm_);
      if (src_inst->is_mvn_) {
        MyAssert(0);
        src_inst->op2_->imm_num_ = -func->stack_size_;
      } else {
        src_inst->op2_->imm_num_ = func->stack_size_;
      }
      if (!Operand2::CheckImm8m(src_inst->op2_->imm_num_)) {
        convert_imm_inst(it);
      } else {
        // 满足op2 可以和后面的add/sub合为一条语句
        merge_with_addsub(it);
      }
    } else if (auto src_inst = dynamic_cast<LdrPseudo *>(*it)) {
      MyAssert(src_inst->IsImm());
      src_inst->imm_ = func->stack_size_;
      if (Operand2::CheckImm8m(src_inst->imm_)) {
        // 满足op2 可以和后面的add/sub合为一条语句
        merge_with_addsub(it);
      }
    } else {
      MyAssert(0);
    }
  }

  func->sp_fixup_.clear();

#ifdef DEBUG_FIXUP_PROCESS
  std::cout << "Fixup sp End." << std::endl;
#endif
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x88, %rsp
movq %rsi, %r14
movq %rsi, 0x10(%rsp)
leaq 0xd8(%rsi), %rdi
movl 0x100(%rsi), %eax
shll $0x2, %eax
addl 0x2c(%rsi), %eax
movq %rax, 0x50(%rsp)
leaq 0x18(%rsp), %rsi
movl $0xe, (%rsi)
callq 0x304ea
movq %rax, 0x48(%rsp)
leaq 0xe0(%r14), %rax
movq %rax, 0x40(%rsp)
movq 0x38(%r14), %rax
movq 0x40(%r14), %rcx
movq %rcx, 0x58(%rsp)
pushq $0x40
popq %r13
cmpq 0x58(%rsp), %rax
je 0x2fbdb
movq %rax, 0x60(%rsp)
movq (%rax), %r15
leaq 0x30(%r15), %rax
movq %rax, 0x20(%rsp)
movq 0x30(%r15), %rbx
movq %r15, 0x38(%rsp)
cmpq 0x38(%r15), %rbx
je 0x2fbcd
movq (%rbx), %rdi
testq %rdi, %rdi
je 0x2fb1b
leaq 0x4fbdf(%rip), %rsi     # 0x7f5f8
leaq 0x4fbc0(%rip), %rdx     # 0x7f5e0
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x2fb1b
movq %rax, %r12
movq %rbx, 0x8(%rsp)
movq 0x18(%rax), %rax
cmpq %rax, 0x20(%r12)
je 0x2fa48
movq %rax, 0x20(%r12)
movq %r12, %r14
addq $0x18, %r14
movl 0x10(%r12), %eax
movl %eax, 0x34(%rsp)
movq 0x10(%rsp), %r15
movq 0xf0(%r15), %rbp
addq $0xe0, %r15
cmpq %r15, %rbp
je 0x2fabe
movl 0x20(%rbp), %ebx
movq %r13, %rdi
callq 0x8250
leaq 0x30(%rax), %rcx
movq %rcx, (%rax)
movq $0x1, 0x8(%rax)
xorps %xmm0, %xmm0
movups %xmm0, 0x10(%rax)
movl $0x3f800000, 0x20(%rax) # imm = 0x3F800000
movups %xmm0, 0x28(%rax)
movl %ebx, 0x38(%rax)
movq %rax, 0x18(%rsp)
movq %r14, %rdi
leaq 0x18(%rsp), %rsi
callq 0x2f726
movq %rbp, %rdi
callq 0x82d0
movq %rax, %rbp
jmp 0x2fa6b
cmpl $0x0, 0x14(%r12)
je 0x2fb01
movq 0x20(%r12), %rax
movq 0x40(%rsp), %rcx
cmpq %rcx, 0x48(%rsp)
movq 0x38(%rsp), %r15
je 0x2faf1
movq -0x8(%rax), %rcx
cmpl $0xe, 0x38(%rcx)
jne 0x2ff2b
movl $0xf, 0x38(%rcx)
cmpq %rax, (%r14)
je 0x2fb24
movq 0x8(%rsp), %rbx
addq $0x8, %rbx
jmp 0x2fb36
movq 0x18(%r12), %rax
cmpq 0x20(%r12), %rax
movq 0x38(%rsp), %r15
je 0x2fbb6
movq 0x8(%rsp), %rbx
addq $0x8, %rbx
jmp 0x2f9fc
movq 0x20(%rsp), %rdi
movq 0x8(%rsp), %rsi
callq 0x30460
movq %rax, %rbx
movq 0x40(%rsp), %rax
cmpq %rax, 0x48(%rsp)
jne 0x2f9fc
movq %rbx, %r12
movq %r13, %rdi
callq 0x8250
movq %rax, %r14
leaq 0x68(%rsp), %rbx
movq %rbx, %rdi
leaq 0x265eb(%rip), %rsi     # 0x5614e
leaq 0x28(%rsp), %rdx
callq 0xa292
movb $0x1, %bpl
andl $0x0, (%rsp)
movq %r14, %rdi
xorl %esi, %esi
pushq $0x1
popq %rdx
movl 0x34(%rsp), %ecx
movq %rbx, %r8
movq %r15, %r9
callq 0x3049a
movq %r14, 0x18(%rsp)
xorl %ebp, %ebp
movq 0x20(%rsp), %rdi
movq %r12, %rsi
leaq 0x18(%rsp), %rdx
callq 0xad0a
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0x8578
jmp 0x2f9fc
movq 0x20(%rsp), %rdi
movq 0x8(%rsp), %rsi
callq 0x30460
movq %rax, %rbx
jmp 0x2f9fc
movq 0x60(%rsp), %rax
addq $0x8, %rax
jmp 0x2f9d7
movq 0x10(%rsp), %rbp
leaq 0x78(%rbp), %r12
leaq 0x4fa0d(%rip), %rbx     # 0x7f5f8
leaq 0x4f9d6(%rip), %r14     # 0x7f5c8
movq (%r12), %r12
testq %r12, %r12
je 0x2fd4e
movq 0x8(%r12), %r13
testq %r13, %r13
je 0x2ff63
movq %r13, %rdi
movq %rbx, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x2ff63
cmpb $0x0, 0x44(%rax)
je 0x2ff63
movl 0x40(%rax), %ecx
movq 0x50(%rsp), %rsi
leal (%rsi,%rcx), %edx
movl %edx, 0x40(%rax)
leal (%rsi,%rcx), %eax
addl $0xfff, %eax            # imm = 0xFFF
cmpl $0x1ffe, %eax           # imm = 0x1FFE
ja 0x2fbf2
movq 0x38(%rbp), %rax
movq 0x40(%rbp), %rcx
cmpq %rcx, %rax
je 0x3014e
movq (%rax), %rbp
movq 0x30(%rbp), %r15
movq 0x38(%rbp), %rdx
cmpq %rdx, %r15
je 0x2fc7c
movq (%r15), %rdi
cmpq %r13, %rdi
je 0x2fc82
addq $0x8, %r15
jmp 0x2fc69
addq $0x8, %rax
jmp 0x2fc55
movq %rbx, %rsi
movq %r14, %rdx
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x30186
movq %rax, %r13
cmpb $0x0, 0x44(%rax)
je 0x30186
addq $0x30, %rbp
movl 0x40(%r13), %eax
movl %eax, 0x8(%rsp)
movq %rbp, %rdi
movq %r15, %rsi
callq 0x30460
movq (%rax), %rdi
testq %rdi, %rdi
je 0x30116
movq %rbx, %rsi
leaq 0x4f8de(%rip), %rdx     # 0x7f5b0
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x30116
movq %rax, %r15
cmpb $0x0, 0x30(%rax)
jne 0x30116
movq 0x38(%r15), %rax
testq %rax, %rax
je 0x30116
movq 0x28(%r15), %rcx
cmpl $0xd, 0x38(%rcx)
jne 0x30116
cmpb $0x0, (%rax)
jne 0x30116
movq 0x8(%rax), %rax
movl 0x38(%rax), %eax
movq 0x18(%r13), %rcx
cmpl 0x38(%rcx), %eax
jne 0x30116
pushq $0x18
popq %rdi
callq 0x8250
movb $0x1, (%rax)
movl 0x8(%rsp), %ecx
movl %ecx, 0x4(%rax)
xorps %xmm0, %xmm0
movups %xmm0, 0x8(%rax)
movq %rax, 0x38(%r15)
movq 0x10(%rsp), %rbp
jmp 0x2fbf2
addq $0x68, %rbp
movq %rbp, %rdi
callq 0x3053c
leaq 0x10(%rsp), %rax
leaq 0x28(%rsp), %rcx
movq %rax, (%rcx)
movq (%rax), %rbp
leaq 0xb0(%rbp), %r14
leaq 0x4f880(%rip), %r15     # 0x7f5f8
leaq 0x4f7b9(%rip), %r12     # 0x7f538
movq (%r14), %r14
testq %r14, %r14
je 0x2ff0a
movq 0x8(%r14), %rbx
testq %rbx, %rbx
je 0x2ff98
movq %rbx, %rdi
movq %r15, %rsi
movq %r12, %rdx
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x2fe12
movq 0x20(%rax), %rcx
cmpb $0x0, (%rcx)
je 0x3009a
cmpb $0x1, 0x14(%rax)
je 0x3005c
movl 0x2c(%rbp), %edi
movl %edi, 0x4(%rcx)
callq 0x9374
testb %al, %al
jne 0x2fe4c
movq 0x10(%rsp), %rcx
movq 0x38(%rcx), %rax
movq 0x40(%rcx), %rcx
cmpq %rcx, %rax
je 0x30021
movq (%rax), %rbp
movq 0x30(%rbp), %r13
movq 0x38(%rbp), %rdx
cmpq %rdx, %r13
je 0x2fe0c
movq (%r13), %rsi
movq 0x8(%r14), %rdi
cmpq %rdi, %rsi
je 0x2fe5e
addq $0x8, %r13
jmp 0x2fdf4
addq $0x8, %rax
jmp 0x2fde0
movq %rbx, %rdi
movq %r15, %rsi
leaq 0x4f7a9(%rip), %rdx     # 0x7f5c8
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x2ff98
cmpb $0x0, 0x44(%rax)
je 0x300d8
movl 0x2c(%rbp), %edi
movl %edi, 0x40(%rax)
callq 0x9374
testb %al, %al
je 0x2ff00
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
callq 0x301f4
jmp 0x2ff00
testq %rsi, %rsi
je 0x2ffd3
movq %r15, %rsi
leaq 0x4f6c7(%rip), %rdx     # 0x7f538
xorl %ecx, %ecx
callq 0x82c0
testq %rax, %rax
je 0x2ffd3
movq %rax, %r12
movq 0x20(%rax), %rax
cmpb $0x0, (%rax)
je 0x2ffd3
leaq 0x30(%rbp), %rbx
movq %rbx, %rdi
movq %r13, %rsi
callq 0x30460
movq %rax, 0x8(%rsp)
movzbl 0x14(%r12), %r13d
movq 0x20(%r12), %rax
negl %r13d
xorl 0x4(%rax), %r13d
pushq $0x48
popq %rdi
callq 0x8250
movq %rax, %r15
movq 0x18(%r12), %rdx
movq %rax, %rdi
xorl %esi, %esi
movl %r13d, %ecx
movq %rbp, %r8
pushq $0x1
popq %r9
callq 0x2d7b6
movq %r15, 0x18(%rsp)
movq %rbx, %rdi
movq 0x8(%rsp), %rsi
leaq 0x18(%rsp), %rdx
callq 0xad0a
leaq 0x4f6ff(%rip), %r15     # 0x7f5f8
leaq 0x4f638(%rip), %r12     # 0x7f538
movq 0x10(%rsp), %rbp
jmp 0x2fd7f
addq $0xa0, %rbp
movq %rbp, %rdi
callq 0x3053c
addq $0x88, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x510b6(%rip), %rdi     # 0x80fe8
leaq 0x261af(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x29655(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x273cc(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x2e
jmp 0x30006
movq 0x5107e(%rip), %rdi     # 0x80fe8
leaq 0x26177(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x2961d(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x27394(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x66
jmp 0x30006
movq 0x51049(%rip), %rdi     # 0x80fe8
leaq 0x26142(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x295e8(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x2735f(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
movq %rax, %rdi
movl $0xc4, %esi
jmp 0x3000a
movq 0x5100e(%rip), %rdi     # 0x80fe8
leaq 0x26107(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x295ad(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x27324(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x7a
popq %rsi
movq %rax, %rdi
callq 0x84b0
movq %rax, %rdi
callq 0x8170
movl $0xff, %edi
callq 0x8300
movq 0x50fc0(%rip), %rdi     # 0x80fe8
leaq 0x260b9(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x2955f(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x272d6(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
movq %rax, %rdi
movl $0x8a, %esi
jmp 0x3000a
movq 0x50f85(%rip), %rdi     # 0x80fe8
leaq 0x2607e(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x29524(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x2729b(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
movq %rax, %rdi
movl $0xb1, %esi
jmp 0x3000a
movq 0x50f47(%rip), %rdi     # 0x80fe8
leaq 0x26040(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x294e6(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x2725d(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
movq %rax, %rdi
movl $0xaf, %esi
jmp 0x3000a
movq 0x50f09(%rip), %rdi     # 0x80fe8
leaq 0x26002(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x294a8(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x2721f(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
movq %rax, %rdi
movl $0xbd, %esi
jmp 0x3000a
movq 0x50ecb(%rip), %rdi     # 0x80fe8
leaq 0x25fc4(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x2946a(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x271e1(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x58
jmp 0x30006
movq 0x50e93(%rip), %rdi     # 0x80fe8
leaq 0x25f8c(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x29432(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x271a9(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x60
jmp 0x30006
movq 0x50e5b(%rip), %rdi     # 0x80fe8
leaq 0x25f54(%rip), %rsi     # 0x560e8
callq 0x8240
leaq 0x293fa(%rip), %rsi     # 0x5959a
movq %rax, %rdi
callq 0x8240
leaq 0x27171(%rip), %rsi     # 0x57320
movq %rax, %rdi
callq 0x8240
pushq $0x51
jmp 0x30006
movq %rax, %rbx
pushq $0x48
popq %rsi
movq %r15, %rdi
jmp 0x301e6
movq %rax, %rbx
jmp 0x301e0
movq %rax, %rbx
leaq 0x68(%rsp), %rdi
callq 0x8578
testb %bpl, %bpl
je 0x301eb
pushq $0x40
popq %rsi
movq %r14, %rdi
callq 0x8260
movq %rbx, %rdi
callq 0x84d0
nop