// File: /workspace/github_cpp_makefile_star2_O1/luooofan[P]hblzbd_compiler/src/Pass/global_value_numbering.cpp
// Function: GlobalValueNumbering::CommenExpressionEliminate(SSABasicBlock*)
void GlobalValueNumbering::CommenExpressionEliminate(SSABasicBlock* bb) {
#ifdef DEBUG_GVN_PROCESS
  std::cout << "  BB: " << bb->GetLabel() << std::endl;
#endif

  int src_vec_size = exp_val_vec.size();

  // compute exp and perform eliminate
  for (auto it = bb->GetInstList().begin(); it != bb->GetInstList().end();) {
    auto inst = *it;
    Expression exp(inst);

    auto find_if_cmp = [&exp](std::pair<Expression, Value*>& kv) {
      if (exp.op_ == kv.first.op_) {
        // 满足交换律的加和乘操作 假设最多只有一个操作数是常数 把常数操作数放后面(之前执行SimpleOptimizePass即满足假设)
        if (exp.op_ == Expression::ADD || exp.op_ == Expression::MUL) {
          if (nullptr != dynamic_cast<ConstantInt*>(exp.operands_[0])) {
            auto temp = exp.operands_[1];
            exp.operands_[1] = exp.operands_[0];
            exp.operands_[0] = temp;
          }
          if (nullptr != dynamic_cast<ConstantInt*>(kv.first.operands_[0])) {
            auto temp = kv.first.operands_[1];
            kv.first.operands_[1] = kv.first.operands_[0];
            kv.first.operands_[0] = temp;
          }
        }
        // 比较每个操作数是否一致 对于常数来说比较的是立即数值 对于其他value来说比较的是指针
        for (int i = 0; i < exp.operands_.size(); ++i) {
          if (auto constint = dynamic_cast<ConstantInt*>(exp.operands_[i])) {
            if (auto constint2 = dynamic_cast<ConstantInt*>(kv.first.operands_[i])) {
              if (constint->GetImm() == constint2->GetImm()) continue;
            } else {
              return false;
            }
          }
          if (exp.operands_[i] != kv.first.operands_[i]) return false;
        }
        return true;
      } else {
        return false;
      }
    };
    auto replace = [&bb, &it](Value* src, Value* target) {
      ++kCount;
#ifdef DEBUG_GVN_PROCESS
      std::cout << "  find redundant: ";
      src->Print(std::cout);
      std::cout << "             ==>: ";
      target->Print(std::cout);
      std::cout << std::endl;
#endif
      src->ReplaceAllUseWith(target);
      it = bb->GetInstList().erase(it);
      delete src;
    };
    auto find_and_replace = [&exp, &it, &find_if_cmp, &replace, this](Value* src) {
      auto vec_it = std::find_if(exp_val_vec.begin(), exp_val_vec.end(), find_if_cmp);
      if (vec_it == exp_val_vec.end()) {
        exp_val_vec.push_back({exp, src});
        ++it;
      } else {
        replace(src, (*vec_it).second);
      }
    };

    // 二元运算语句
    if (auto src_inst = dynamic_cast<BinaryOperator*>(inst)) {
      switch (src_inst->op_) {
        case BinaryOperator::ADD:
          exp.op_ = Expression::ADD;
          break;
        case BinaryOperator::SUB:
          exp.op_ = Expression::SUB;
          break;
        case BinaryOperator::MUL:
          exp.op_ = Expression::MUL;
          break;
        case BinaryOperator::DIV:
          exp.op_ = Expression::DIV;
          break;
        case BinaryOperator::MOD:
          exp.op_ = Expression::MOD;
          break;
        default:
          MyAssert(0);
          break;
      }
      exp.operands_.push_back(src_inst->GetOperand(0));
      exp.operands_.push_back(src_inst->GetOperand(1));

      find_and_replace(src_inst);
    }
    // 一元运算语句
    else if (auto src_inst = dynamic_cast<UnaryOperator*>(inst)) {
      switch (src_inst->op_) {
        case UnaryOperator::NEG:
          exp.op_ = Expression::NEG;
          break;
        case UnaryOperator::NOT:
          exp.op_ = Expression::NOT;
          break;
        default:
          MyAssert(0);
          break;
      }
      exp.operands_.push_back(src_inst->GetOperand(0));

      find_and_replace(src_inst);
    }
    // Call语句 需要关注call的函数是否有副作用 有副作用则不可删 kill掉原来的
    else if (auto src_inst = dynamic_cast<CallInst*>(inst)) {
      auto func_val = dynamic_cast<FunctionValue*>(src_inst->GetOperand(0));
      MyAssert(nullptr != func_val);
      // 如果调用了有副作用的函数 不用处理该语句
      if (no_side_effect_funcs.find(func_val->GetFunction()) == no_side_effect_funcs.end()) {
        // TODO: 这里可以考虑把该基本块内的load exp都kill掉
        ++it;
        continue;
      }
      // 调用了void函数也可以算作表达式 虽然没有使用 但是可以删除一条多余的call
      // 如果前面做了死代码消除 不应该出现调用无副作用void函数的call语句

      // Expression exp(Expression::CALL);
      exp.op_ = Expression::CALL;
      for (int i = 0; i < src_inst->GetNumOperands(); ++i) {
        exp.operands_.push_back(src_inst->GetOperand(i));
      }

      find_and_replace(src_inst);
    }
    // Load语句 如果找到一条公共的load语句 需要检查从该语句开始到当前语句的所有执行路径上都没有对target的store语句
    else if (auto src_inst = dynamic_cast<LoadInst*>(inst)) {
      exp.op_ = Expression::LOAD;
      for (int i = 0; i < src_inst->GetNumOperands(); ++i) {
        exp.operands_.push_back(src_inst->GetOperand(i));
      }

      auto check_inst_range = [this](std::list<SSAInstruction*>::iterator begin,
                                     std::list<SSAInstruction*>::iterator end, LoadInst* target) {
        Value* memory = target->GetOperand(0);
        for (; begin != end; ++begin) {
          // 是调用了有副作用函数的call语句
          auto call_inst = dynamic_cast<CallInst*>(*begin);
          if (nullptr != call_inst) {
            auto func_val = dynamic_cast<FunctionValue*>(call_inst->GetOperand(0));
            if (no_side_effect_funcs.find(func_val->GetFunction()) == no_side_effect_funcs.end()) {
              return false;
            }
          }

          // 是对同一块内存区域的store语句
          auto store_inst = dynamic_cast<StoreInst*>(*begin);
          if (nullptr != store_inst && store_inst->GetOperand(1) == memory) {
            // 如果load和store语句的偏移都是常量的话可以比较立即数 如果不同 则跳过这条store语句
            // NOTE: 都有偏移 要么都有 要么都没 不会出现一个有一个没有
            if (target->GetNumOperands() == 2 && store_inst->GetNumOperands() == 3) {
              if (auto constint = dynamic_cast<ConstantInt*>(target->GetOperand(1))) {
                if (auto constint2 = dynamic_cast<ConstantInt*>(store_inst->GetOperand(2))) {
                  if (constint->GetImm() != constint2->GetImm()) continue;
                }
              }
            }
            return false;
          }
        }
        return true;
      };

      auto check = [this, &check_inst_range](SSAInstruction* source, LoadInst* target) {
        // 检查从source指令开始到target指定的所有路径上有没有对同一块内存区域的store语句或者对副作用函数的调用语句
        // source可能是load或store target一定是load
        // source->Print(std::cout);
        // target->Print(std::cout);
        auto source_bb = source->GetParent();
        auto target_bb = target->GetParent();
        // 1 if source and target in the same bb
        if (source_bb == target_bb) {
          auto inst_list = source_bb->GetInstList();
          auto st = ++std::find(inst_list.begin(), inst_list.end(), source),
               ed = std::find(st, inst_list.end(), target);
          return check_inst_range(st, ed, target);
        }
        // 2 in different bbs
        // NOTE: 好像会导致更多的溢出 禁用 等决赛可以取消禁用提交一次
        else {
          // return false;
          // 2.1 check source bb
          auto src_inst_list = source_bb->GetInstList();
          if (!check_inst_range(++std::find(src_inst_list.begin(), src_inst_list.end(), source), src_inst_list.end(),
                                target))
            return false;
          // std::cout << 1 << std::endl;
          // 2.2 check target bb
          auto tar_inst_list = target_bb->GetInstList();
          if (!check_inst_range(tar_inst_list.begin(), std::find(tar_inst_list.begin(), tar_inst_list.end(), target),
                                target))
            return false;
          // std::cout << 2 << std::endl;
          // 2.3 check all reached bb in road
          std::unordered_set<SSABasicBlock*> src_reach;
          std::unordered_set<SSABasicBlock*> tar_reach;
          std::queue<SSABasicBlock*> q;
          std::unordered_set<SSABasicBlock*> vis;
          auto dfs = [&q, &vis](std::unordered_set<SSABasicBlock*>& reach, bool succ = true) {
            while (!q.empty()) {
              auto front = q.front();
              reach.insert(front);
              q.pop();
              for (auto next_bb : (succ ? front->GetSuccBB() : front->GetPredBB())) {
                if (vis.count(next_bb)) continue;
                q.push(next_bb);
                vis.insert(next_bb);
              }
            }
            vis.clear();
          };

          // 2.3.1 fill src_reach
          q.push(source_bb);
          vis.insert(source_bb);
          dfs(src_reach, true);

          // 2.3.2 fill tar_reach
          q.push(target_bb);
          vis.insert(target_bb);
          dfs(tar_reach, false);

          // 2.3.3 compute cross set
          std::unordered_set<SSABasicBlock*> reached_bb;
          for (auto reach_bb : src_reach)
            if (tar_reach.count(reach_bb)) reached_bb.insert(reach_bb);

          // 2.3.4 determine source_bb and target_bb whether in road or not(just end point).
          if (!bbs_in_loop.count(source_bb)) reached_bb.erase(source_bb);
          if (!bbs_in_loop.count(target_bb)) reached_bb.erase(target_bb);

          // 2.3.5 check all bbs in road
          for (auto bb : reached_bb) {
            auto inst_list = bb->GetInstList();
            if (!check_inst_range(inst_list.begin(), inst_list.end(), target)) return false;
          }

          // std::cout << 3 << std::endl;
          return true;
        }
      };

      // NOTE: reverse find 保证找到最新的一个
      auto vec_it = std::find_if(exp_val_vec.rbegin(), exp_val_vec.rend(), find_if_cmp);
      if (vec_it == exp_val_vec.rend()) {
        exp_val_vec.push_back({exp, src_inst});
        ++it;
      } else {
        // check决定能否replace if check true, perform replace. otherwise add exp to exp_val_vec
        if (check((*vec_it).first.inst_, src_inst)) {
          replace(src_inst, (*vec_it).second);
        } else {
          exp_val_vec.push_back({exp, src_inst});
          ++it;
        }
      }
    }
    // Store语句 可以看成一条load语句 同时或许可以kill掉该基本块内的对同一块内存操作的load语句
    else if (auto src_inst = dynamic_cast<StoreInst*>(inst)) {
      exp.op_ = Expression::LOAD;
      for (int i = 1; i < src_inst->GetNumOperands(); ++i) {
        exp.operands_.push_back(src_inst->GetOperand(i));
      }

      // 不管有没有 直接加进去即可 之后再找相同的load exp 保证找到最新(靠后)的一个就行
      exp_val_vec.push_back({exp, src_inst->GetOperand(0)});
      ++it;
    }
    // 其他语句
    else {
      ++it;
    }
  }

  // traverse dom tree
  for (auto dom : bb->GetDoms()) {
    CommenExpressionEliminate(dom);
  }

  // erase now bb exps from exp_val_vec
  exp_val_vec.erase(exp_val_vec.begin() + src_vec_size, exp_val_vec.end());
}

// Assembly:
pushq %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x258, %rsp            # imm = 0x258
movq %rsi, 0xd8(%rsp)
leaq 0xa8(%rdi), %r12
movq 0xa8(%rdi), %rax
movq %rax, 0x118(%rsp)
movq 0xb0(%rdi), %rax
movq %rax, 0x120(%rsp)
leaq 0x28(%rsi), %rax
movq 0x28(%rsi), %r13
movq %r13, 0x8(%rsp)
cmpq %rax, %r13
movq %rdi, 0xa8(%rsp)
je 0x539ef
leaq 0x70(%rdi), %rax
movq %rax, 0xb8(%rsp)
leaq 0x8(%rsp), %rbp
movq %r12, 0xa0(%rsp)
movq 0x10(%r13), %r15
leaq 0x28(%rsp), %rax
xorps %xmm0, %xmm0
movups %xmm0, (%rax)
movq $0x0, 0x10(%rax)
movq %r15, 0x40(%rsp)
leaq 0x20(%rsp), %rax
movq %rax, 0xd0(%rsp)
leaq 0xd8(%rsp), %rcx
movq %rcx, 0xc0(%rsp)
movq %rbp, 0xc8(%rsp)
movq %rax, 0x188(%rsp)
movq %rbp, 0x190(%rsp)
leaq 0xd0(%rsp), %rax
movq %rax, 0x198(%rsp)
leaq 0xc0(%rsp), %rax
movq %rax, 0x1a0(%rsp)
movq 0xa8(%rsp), %rax
movq %rax, 0x1a8(%rsp)
testq %r15, %r15
je 0x52e28
movq %r15, %rdi
leaq 0x3c5e3(%rip), %rsi     # 0x8f3f8
leaq 0x3c814(%rip), %rdx     # 0x8f630
xorl %ecx, %ecx
callq 0x8320
movq %rax, %rbx
jmp 0x52e2a
xorl %ebx, %ebx
testq %rbx, %rbx
je 0x52e5e
movl 0x68(%rbx), %eax
cmpq $0x4, %rax
ja 0x53a67
leaq 0x1faa9(%rip), %rcx     # 0x728ec
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
leaq 0x50(%rsp), %r14
jmpq *%rax
movl $0x0, 0x20(%rsp)
jmp 0x52f2a
testq %r15, %r15
je 0x52e80
movq %r15, %rdi
leaq 0x3c58b(%rip), %rsi     # 0x8f3f8
leaq 0x3c7fc(%rip), %rdx     # 0x8f670
xorl %ecx, %ecx
callq 0x8320
movq %rax, %rbx
jmp 0x52e82
xorl %ebx, %ebx
testq %rbx, %rbx
je 0x52edb
movl 0x68(%rbx), %ecx
movl $0x5, %eax
testl %ecx, %ecx
leaq 0x50(%rsp), %r14
je 0x52ea6
cmpl $0x1, %ecx
jne 0x53acd
movl $0x6, %eax
movl %eax, 0x20(%rsp)
movq %rbx, %rdi
xorl %esi, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
callq 0x554e0
leaq 0x188(%rsp), %rdi
movq %rbx, %rsi
callq 0x53d2e
jmp 0x52f75
testq %r15, %r15
je 0x52fab
movq %r15, %rdi
leaq 0x3c50a(%rip), %rsi     # 0x8f3f8
leaq 0x3c7fb(%rip), %rdx     # 0x8f6f0
xorl %ecx, %ecx
callq 0x8320
movq %rax, %rbx
jmp 0x52fad
movl $0x4, 0x20(%rsp)
jmp 0x52f2a
movl $0x2, 0x20(%rsp)
jmp 0x52f2a
movl $0x3, 0x20(%rsp)
jmp 0x52f2a
movl $0x1, 0x20(%rsp)
movq %rbx, %rdi
xorl %esi, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
callq 0x554e0
movq %rbx, %rdi
movl $0x1, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r14, %rsi
callq 0x554e0
leaq 0x188(%rsp), %rdi
movq %rbx, %rsi
callq 0x53d2e
movq 0x28(%rsp), %rdi
testq %rdi, %rdi
je 0x52f8c
movq 0x38(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq 0xd8(%rsp), %rsi
leaq 0x28(%rsi), %rax
movq 0x8(%rsp), %r13
cmpq %rax, %r13
jne 0x52d85
jmp 0x539ef
xorl %ebx, %ebx
testq %rbx, %rbx
je 0x52fe0
movq %rbx, %rdi
xorl %esi, %esi
callq 0x33480
leaq 0x50(%rsp), %r15
testq %rax, %rax
je 0x53009
movq %rax, %rdi
leaq 0x3c4e0(%rip), %rsi     # 0x8f4b0
leaq 0x3c531(%rip), %rdx     # 0x8f508
xorl %ecx, %ecx
callq 0x8320
jmp 0x5300b
testq %r15, %r15
je 0x5308b
movq %r15, %rdi
leaq 0x3c405(%rip), %rsi     # 0x8f3f8
leaq 0x3c7b6(%rip), %rdx     # 0x8f7b0
xorl %ecx, %ecx
callq 0x8320
movq %rax, %r14
jmp 0x5308e
xorl %eax, %eax
testq %rax, %rax
je 0x53b30
movq 0x60(%rax), %rcx
movq 0xa8(%rsp), %rax
movq 0x38(%rax), %rdi
movq 0x40(%rax), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq %rdx, %rsi
movq (%rdi,%rdx,8), %rdx
movl $0x0, %eax
testq %rdx, %rdx
je 0x53237
movq (%rdx), %r9
movq %rdx, %rax
cmpq 0x8(%r9), %rcx
je 0x53237
movq %r9, %r10
movq (%r9), %r9
testq %r9, %r9
je 0x53235
movq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
movl $0x0, %eax
cmpq %rsi, %rdx
jne 0x53237
movq %r10, %rax
cmpq %rdi, %rcx
jne 0x53055
jmp 0x53237
xorl %r14d, %r14d
testq %r14, %r14
je 0x5320f
movl $0x8, 0x20(%rsp)
movq 0x50(%r14), %rax
subq 0x48(%r14), %rax
movabsq $0xffffffff0, %rcx      # imm = 0xFFFFFFFF0
testq %rcx, %rax
leaq 0x50(%rsp), %r15
je 0x530eb
xorl %ebx, %ebx
movq %r14, %rdi
movl %ebx, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r15, %rsi
callq 0x554e0
incl %ebx
movq 0x50(%r14), %rax
subq 0x48(%r14), %rax
shrq $0x4, %rax
cmpl %eax, %ebx
jb 0x530bd
movq 0xa8(%rsp), %rax
movq %rax, 0xb0(%rsp)
movq 0xa8(%rax), %rcx
movq 0xb0(%rax), %r12
movq 0xd0(%rsp), %rax
movq %rax, 0x50(%rsp)
movq %r12, %r13
movq %rcx, 0x10(%rsp)
subq %rcx, %r13
sarq $0x4, %r13
movabsq $-0x5555555555555555, %rax # imm = 0xAAAAAAAAAAAAAAAB
imulq %rax, %r13
sarq $0x2, %r13
testq %r13, %r13
jle 0x531b2
incq %r13
leaq -0x30(%r12), %r15
leaq 0x50(%rsp), %rbp
movq %rbp, %rdi
movq %r15, %rsi
callq 0x54474
testb %al, %al
jne 0x53370
leaq -0x60(%r12), %rbx
movq %rbp, %rdi
movq %rbx, %rsi
callq 0x54474
testb %al, %al
jne 0x53368
leaq -0x90(%r12), %r15
movq %rbp, %rdi
movq %r15, %rsi
callq 0x54474
testb %al, %al
jne 0x5336d
addq $-0xc0, %r12
movq %rbp, %rdi
movq %r12, %rsi
callq 0x54474
testb %al, %al
jne 0x533af
decq %r13
cmpq $0x1, %r13
jg 0x5313f
movq %r12, %rax
movq 0x10(%rsp), %rbx
subq %rbx, %rax
sarq $0x4, %rax
movabsq $-0x5555555555555555, %rcx # imm = 0xAAAAAAAAAAAAAAAB
imulq %rcx, %rax
cmpq $0x1, %rax
je 0x53390
cmpq $0x2, %rax
leaq 0x50(%rsp), %r13
je 0x53375
cmpq $0x3, %rax
jne 0x533aa
leaq -0x30(%r12), %rbp
movq %r13, %rdi
movq %rbp, %rsi
callq 0x54474
testb %al, %al
je 0x53378
jmp 0x533b7
testq %r15, %r15
je 0x532b2
movq %r15, %rdi
leaq 0x3c1d6(%rip), %rsi     # 0x8f3f8
leaq 0x3c5c7(%rip), %rdx     # 0x8f7f0
xorl %ecx, %ecx
callq 0x8320
movq %rax, %rbx
jmp 0x532b4
xorl %eax, %eax
testq %rax, %rax
je 0x539dd
cmpq $0x0, (%rax)
je 0x539dd
movl $0x7, 0x20(%rsp)
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
movabsq $0xffffffff0, %rcx      # imm = 0xFFFFFFFF0
testq %rcx, %rax
je 0x5329d
xorl %r14d, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r15, %rsi
callq 0x554e0
incl %r14d
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
shrq $0x4, %rax
cmpl %eax, %r14d
jb 0x5326c
leaq 0x188(%rsp), %rdi
movq %rbx, %rsi
callq 0x53d2e
jmp 0x52f75
xorl %ebx, %ebx
testq %rbx, %rbx
je 0x5335f
movl $0x8, 0x20(%rsp)
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
movabsq $0xffffffff0, %rcx      # imm = 0xFFFFFFFF0
addq $-0x10, %rcx
testq %rcx, %rax
leaq 0x50(%rsp), %r15
je 0x5331c
movl $0x1, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x33480
movq %rax, 0x50(%rsp)
leaq 0x28(%rsp), %rdi
movq %r15, %rsi
callq 0x554e0
incl %r14d
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
shrq $0x4, %rax
cmpl %eax, %r14d
jb 0x532eb
movq %rbx, %rdi
xorl %esi, %esi
callq 0x33480
movq %rax, %rbx
movl 0x20(%rsp), %eax
movl %eax, 0x50(%rsp)
leaq 0x58(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x549e8
movq 0x40(%rsp), %rax
movq %rax, 0x70(%rsp)
movq %rbx, 0x78(%rsp)
movq %r12, %rdi
movq %r15, %rsi
callq 0x551e4
jmp 0x539c6
movq (%r13), %rax
jmp 0x539e5
movq %r15, %r12
jmp 0x53370
movq %rbx, %r12
movq %rbp, %r13
jmp 0x533b7
movq %r12, %rbp
leaq -0x30(%rbp), %r15
movq %r13, %rdi
movq %r15, %rsi
callq 0x54474
movq %rbp, %r12
testb %al, %al
je 0x53398
jmp 0x533b7
movq %r12, %r15
leaq 0x50(%rsp), %r13
leaq -0x30(%r15), %rsi
movq %r13, %rdi
callq 0x54474
testb %al, %al
cmovneq %r15, %rbx
movq %rbx, %r12
jmp 0x533b7
movq %r15, %r12
leaq 0x50(%rsp), %r13
movq 0xa0(%rsp), %rax
cmpq (%rax), %r12
je 0x53592
movq -0x10(%r12), %rbx
movq 0x60(%rbx), %rax
movq %rax, 0x48(%rsp)
movq 0x60(%r14), %rcx
movq %rcx, 0x18(%rsp)
leaq 0x28(%rax), %rsi
cmpq %rcx, %rax
leaq 0x170(%rsp), %r15
je 0x535d5
movq %r15, %rdi
callq 0x54a84
leaq 0x8(%rsp), %rbp
movq 0x170(%rsp), %rax
cmpq %r15, %rax
je 0x53419
cmpq %rbx, 0x10(%rax)
je 0x53419
movq (%rax), %rax
jmp 0x53409
movq (%rax), %rsi
leaq 0xb0(%rsp), %rdi
movq %r15, %rdx
movq %r14, %rcx
callq 0x5460e
testb %al, %al
je 0x5364e
movq 0x18(%rsp), %rsi
addq $0x28, %rsi
leaq 0xe8(%rsp), %rbx
movq %rbx, %rdi
callq 0x54a84
movq 0xe8(%rsp), %rsi
movq %rsi, %rdx
cmpq %rbx, %rsi
je 0x53479
movq %rsi, %rdx
cmpq %r14, 0x10(%rdx)
je 0x53479
movq (%rdx), %rdx
leaq 0xe8(%rsp), %rax
cmpq %rax, %rdx
jne 0x53463
leaq 0xb0(%rsp), %rdi
movq %r14, %rcx
callq 0x5460e
testb %al, %al
je 0x5365b
leaq 0x250(%rsp), %rax
movq %rax, 0x220(%rsp)
movl $0x1, %ecx
movq %rcx, 0x228(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, %edx       # imm = 0x3F800000
movl %edx, 0x240(%rsp)
movups %xmm0, -0x8(%rax)
leaq 0x218(%rsp), %rax
movq %rax, 0x1e8(%rsp)
movq %rcx, 0x1f0(%rsp)
movups %xmm0, -0x20(%rax)
movl %edx, 0x208(%rsp)
movups %xmm0, -0x8(%rax)
movaps %xmm0, 0x90(%rsp)
movaps %xmm0, 0x80(%rsp)
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movaps %xmm0, 0x50(%rsp)
movq %r13, %rdi
xorl %esi, %esi
callq 0x54d8c
leaq 0x1e0(%rsp), %rax
movq %rax, 0x1b0(%rsp)
movq $0x1, 0x1b8(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, 0x1d0(%rsp) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq %r13, 0x160(%rsp)
leaq 0x1b0(%rsp), %rax
movq %rax, 0x168(%rsp)
movq 0x80(%rsp), %rax
movq 0x90(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x53668
movq 0x48(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x80(%rsp)
jmp 0x53675
movl 0x20(%rsp), %eax
movl %eax, 0x50(%rsp)
leaq 0x58(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x549e8
movq 0x40(%rsp), %rax
movq %rax, 0x70(%rsp)
movq %r14, 0x78(%rsp)
movq 0xa0(%rsp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x551e4
leaq 0x8(%rsp), %rbp
jmp 0x539c6
movq %r13, %rdi
callq 0x54a84
leaq 0x8(%rsp), %rbp
movq 0x50(%rsp), %rax
cmpq %r13, %rax
je 0x535f7
cmpq %rbx, 0x10(%rax)
je 0x535f7
movq (%rax), %rax
jmp 0x535e7
movq (%rax), %rsi
movq %rsi, %rdx
cmpq %r13, %rsi
je 0x53613
movq %rsi, %rdx
cmpq %r14, 0x10(%rdx)
je 0x53613
movq (%rdx), %rdx
cmpq %r13, %rdx
jne 0x53605
leaq 0xb0(%rsp), %rdi
movq %r14, %rcx
callq 0x5460e
movl %eax, %r15d
movq 0x50(%rsp), %rdi
cmpq %r13, %rdi
je 0x53921
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %r13, %rbx
jne 0x53634
jmp 0x53921
movl $0x0, 0x10(%rsp)
jmp 0x538fa
movl $0x0, 0x10(%rsp)
jmp 0x538cb
movq %r13, %rdi
leaq 0x48(%rsp), %rsi
callq 0x54f02
leaq 0x1b0(%rsp), %rdi
movq %rdi, 0x128(%rsp)
leaq 0x48(%rsp), %rsi
leaq 0x128(%rsp), %rdx
callq 0x3632c
leaq 0x160(%rsp), %rdi
leaq 0x220(%rsp), %rsi
movl $0x1, %edx
callq 0x54848
movq 0x80(%rsp), %rax
movq 0x90(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x536dd
movq 0x18(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x80(%rsp)
jmp 0x536ea
movq %r13, %rdi
leaq 0x18(%rsp), %rsi
callq 0x54f02
leaq 0x1b0(%rsp), %rdi
movq %rdi, 0x128(%rsp)
leaq 0x18(%rsp), %rsi
leaq 0x128(%rsp), %rdx
callq 0x3632c
leaq 0x160(%rsp), %rdi
leaq 0x1e8(%rsp), %rsi
xorl %edx, %edx
callq 0x54848
leaq 0x158(%rsp), %rax
movq %rax, 0x128(%rsp)
movq $0x1, 0x130(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, 0x148(%rsp) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq 0x230(%rsp), %rbx
testq %rbx, %rbx
je 0x537b2
movq 0x8(%rbx), %rax
movq %rax, 0xe0(%rsp)
leaq 0x1e8(%rsp), %rdi
leaq 0xe0(%rsp), %rsi
callq 0x54bfc
testq %rax, %rax
je 0x537ad
leaq 0x128(%rsp), %rdi
movq %rdi, 0x100(%rsp)
leaq 0xe0(%rsp), %rsi
leaq 0x100(%rsp), %rdx
callq 0x3632c
movq (%rbx), %rbx
jmp 0x5375d
movq 0xb8(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x54bfc
testq %rax, %rax
jne 0x537db
leaq 0x128(%rsp), %rdi
leaq 0x48(%rsp), %rsi
callq 0x54b16
movq 0xb8(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x54bfc
testq %rax, %rax
jne 0x53804
leaq 0x128(%rsp), %rdi
leaq 0x18(%rsp), %rsi
callq 0x54b16
movq 0x138(%rsp), %rbx
testq %rbx, %rbx
sete %al
movl %eax, 0x10(%rsp)
je 0x53887
movq 0x8(%rbx), %rsi
addq $0x28, %rsi
leaq 0x100(%rsp), %r13
movq %r13, %rdi
callq 0x54a84
movq 0x100(%rsp), %rsi
leaq 0xb0(%rsp), %rdi
movq %r13, %rdx
movq %r14, %rcx
callq 0x5460e
movl %eax, %r15d
movq 0x100(%rsp), %rdi
cmpq %r13, %rdi
je 0x53873
movq %r13, %rbp
movq (%rdi), %r13
movl $0x18, %esi
callq 0x82a0
movq %r13, %rdi
cmpq %rbp, %r13
jne 0x5385e
testb %r15b, %r15b
leaq 0x50(%rsp), %r13
leaq 0x8(%rsp), %rbp
je 0x53887
movq (%rbx), %rbx
jmp 0x5380c
leaq 0x128(%rsp), %rdi
callq 0x362bc
leaq 0x1b0(%rsp), %rdi
callq 0x362bc
movq %r13, %rdi
callq 0x54948
leaq 0x1e8(%rsp), %rdi
callq 0x362bc
leaq 0x220(%rsp), %rdi
callq 0x362bc
leaq 0x170(%rsp), %r15
movq 0xe8(%rsp), %rdi
leaq 0xe8(%rsp), %r13
cmpq %r13, %rdi
je 0x538f5
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %r13, %rbx
jne 0x538e0
leaq 0x50(%rsp), %r13
movq 0x170(%rsp), %rdi
cmpq %r15, %rdi
je 0x5391c
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %r15, %rbx
jne 0x53907
movl 0x10(%rsp), %r15d
testb $0x1, %r15b
je 0x5398d
movq -0x8(%r12), %rsi
incl 0x3cdb2(%rip)           # 0x906e4
movq %r14, %rdi
callq 0x3327c
movq 0xc0(%rsp), %rax
movq 0xc8(%rsp), %rcx
movq (%rax), %rax
movq (%rcx), %rbx
movq (%rbx), %r15
decq 0x38(%rax)
movq %rbx, %rdi
callq 0x84d0
movl $0x18, %esi
movq %rbx, %rdi
callq 0x82a0
movq 0xc8(%rsp), %rax
movq %r15, (%rax)
movq (%r14), %rax
movq %r14, %rdi
callq *0x8(%rax)
movq 0xa0(%rsp), %r12
jmp 0x52f75
movl 0x20(%rsp), %eax
movl %eax, 0x50(%rsp)
leaq 0x58(%rsp), %rdi
leaq 0x28(%rsp), %rsi
callq 0x549e8
movq 0x40(%rsp), %rax
movq %rax, 0x70(%rsp)
movq %r14, 0x78(%rsp)
movq 0xa0(%rsp), %r12
movq %r12, %rdi
movq %r13, %rsi
callq 0x551e4
movq 0x58(%rsp), %rdi
testq %rdi, %rdi
je 0x539dd
movq 0x68(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq 0x8(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x8(%rsp)
jmp 0x52f75
movq 0x78(%rsi), %rbx
movq 0x80(%rsi), %r14
cmpq %r14, %rbx
movq 0xa8(%rsp), %r15
je 0x53a1b
movq (%rbx), %rsi
movq %r15, %rdi
callq 0x52d10
addq $0x8, %rbx
cmpq %r14, %rbx
jne 0x53a07
movq 0x120(%rsp), %rax
subq 0x118(%rsp), %rax
shrq $0x4, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
cltq
leaq (%rax,%rax,2), %rsi
shlq $0x4, %rsi
addq 0xa8(%r15), %rsi
movq 0xb0(%r15), %rdx
movq %r12, %rdi
callq 0x55630
addq $0x258, %rsp            # imm = 0x258
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3c582(%rip), %rdi     # 0x8fff0
leaq 0x1b6f3(%rip), %rsi     # 0x6f168
movl $0x8, %edx
callq 0x8330
movq 0x3c56a(%rip), %rdi     # 0x8fff0
leaq 0x1ee8a(%rip), %rsi     # 0x72917
movl $0x23, %edx
callq 0x8330
movq 0x3c552(%rip), %rdi     # 0x8fff0
leaq 0x1c91b(%rip), %rsi     # 0x703c0
movl $0x1, %edx
callq 0x8330
movq 0x3c53a(%rip), %rdi     # 0x8fff0
movl $0xa5, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
jmp 0x53b91
movq 0x3c51c(%rip), %rdi     # 0x8fff0
leaq 0x1b68d(%rip), %rsi     # 0x6f168
movl $0x8, %edx
callq 0x8330
movq 0x3c504(%rip), %rdi     # 0x8fff0
leaq 0x1ee24(%rip), %rsi     # 0x72917
movl $0x23, %edx
callq 0x8330
movq 0x3c4ec(%rip), %rdi     # 0x8fff0
leaq 0x1c8b5(%rip), %rsi     # 0x703c0
movl $0x1, %edx
callq 0x8330
movq 0x3c4d4(%rip), %rdi     # 0x8fff0
movl $0xb7, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
jmp 0x53b91
movq 0x3c4b9(%rip), %rdi     # 0x8fff0
leaq 0x1b62a(%rip), %rsi     # 0x6f168
movl $0x8, %edx
callq 0x8330
movq 0x3c4a1(%rip), %rdi     # 0x8fff0
leaq 0x1edc1(%rip), %rsi     # 0x72917
movl $0x23, %edx
callq 0x8330
movq 0x3c489(%rip), %rdi     # 0x8fff0
leaq 0x1c852(%rip), %rsi     # 0x703c0
movl $0x1, %edx
callq 0x8330
movq 0x3c471(%rip), %rdi     # 0x8fff0
movl $0xc1, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
movl $0xff, %edi
callq 0x8380
movq %rax, %rbx
jmp 0x53c7f
movq %rax, %rbx
jmp 0x53c99
jmp 0x53c0b
movq %rax, %rbx
movq 0x50(%rsp), %rdi
cmpq %r13, %rdi
je 0x53d0e
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r13, %r14
jne 0x53bbe
jmp 0x53d0e
jmp 0x53c58
jmp 0x53be3
jmp 0x53d0b
jmp 0x53be3
movq %rax, %rbx
movq 0x58(%rsp), %rdi
testq %rdi, %rdi
je 0x53d0e
movq 0x68(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
jmp 0x53d0e
jmp 0x53d0b
movq %rax, %rbx
jmp 0x53ccb
movq %rax, %rbx
jmp 0x53c68
jmp 0x53d0b
jmp 0x53d0b
movq %rax, %rbx
movq 0x100(%rsp), %rdi
cmpq %r13, %rdi
je 0x53c5b
leaq 0x100(%rsp), %r15
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x53c3a
jmp 0x53c5b
jmp 0x53c58
jmp 0x53d0b
movq %rax, %rbx
leaq 0x128(%rsp), %rdi
callq 0x362bc
leaq 0x1b0(%rsp), %rdi
callq 0x362bc
leaq 0x50(%rsp), %rdi
callq 0x54948
leaq 0x1e8(%rsp), %rdi
callq 0x362bc
leaq 0x220(%rsp), %rdi
callq 0x362bc
movq 0xe8(%rsp), %rdi
leaq 0xe8(%rsp), %rax
cmpq %rax, %rdi
je 0x53ccb
leaq 0xe8(%rsp), %r15
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x53cb6
movq 0x170(%rsp), %rdi
leaq 0x170(%rsp), %r15
cmpq %r15, %rdi
je 0x53d0e
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x53ce0
jmp 0x53d0e
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
jmp 0x53d0b
movq %rax, %rbx
movq 0x28(%rsp), %rdi
testq %rdi, %rdi
je 0x53d25
movq 0x38(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq %rbx, %rdi
callq 0x8540
nop