// File: /workspace/github_cpp_makefile_star2_O3/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 $0x268, %rsp            # imm = 0x268
movq %rdi, %r12
movq %rsi, 0xf8(%rsp)
leaq 0xa8(%rdi), %r15
movq 0xa8(%rdi), %rax
movq %rax, 0x138(%rsp)
movq 0xb0(%rdi), %rax
movq %rax, 0x140(%rsp)
leaq 0x28(%rsi), %rax
movq 0x28(%rsi), %rbp
movq %rbp, 0x8(%rsp)
cmpq %rax, %rbp
je 0x52d52
leaq 0x38(%r12), %rax
movq %rax, 0x130(%rsp)
leaq 0x70(%r12), %rax
movq %rax, 0xd8(%rsp)
movq %r15, 0x50(%rsp)
movq 0x10(%rbp), %r14
leaq 0x30(%rsp), %rax
xorps %xmm0, %xmm0
movups %xmm0, (%rax)
movq $0x0, 0x10(%rax)
movq %r14, 0x48(%rsp)
leaq 0x28(%rsp), %rax
movq %rax, 0xf0(%rsp)
leaq 0xf8(%rsp), %rcx
movq %rcx, 0xe0(%rsp)
leaq 0x8(%rsp), %rcx
movq %rcx, 0xe8(%rsp)
movq %rax, 0x198(%rsp)
movq %rcx, 0x1a0(%rsp)
leaq 0xf0(%rsp), %rax
movq %rax, 0x1a8(%rsp)
leaq 0xe0(%rsp), %rax
movq %rax, 0x1b0(%rsp)
movq %r12, 0x1b8(%rsp)
testq %r14, %r14
je 0x525f4
movq %r14, %rdi
leaq 0x3c265(%rip), %r13     # 0x8e3c8
movq %r13, %rsi
leaq 0x3c493(%rip), %rdx     # 0x8e600
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
je 0x521ab
movq %rax, %rbx
movl 0x68(%rax), %eax
cmpq $0x4, %rax
ja 0x52e27
leaq 0x1f760(%rip), %rcx     # 0x718f0
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
leaq 0x60(%rsp), %r14
jmpq *%rax
movl $0x0, 0x28(%rsp)
jmp 0x52324
movq %r14, %rdi
movq %r13, %rsi
leaq 0x3c488(%rip), %rdx     # 0x8e640
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
je 0x5221b
movq %rax, %rbx
movl 0x68(%rax), %ecx
movl $0x5, %eax
testl %ecx, %ecx
leaq 0x60(%rsp), %r14
je 0x521e6
cmpl $0x1, %ecx
jne 0x52e8a
movl $0x6, %eax
movl %eax, 0x28(%rsp)
movq %rbx, %rdi
xorl %esi, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0x54786
leaq 0x198(%rsp), %rdi
movq %rbx, %rsi
callq 0x5308a
jmp 0x525fd
movq %r14, %rdi
movq %r13, %rsi
leaq 0x3c498(%rip), %rdx     # 0x8e6c0
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
je 0x52374
movq %rax, %rbx
movq %rax, %rdi
xorl %esi, %esi
callq 0x335d4
leaq 0x60(%rsp), %r13
testq %rax, %rax
je 0x52dc1
movq %rax, %rdi
leaq 0x3c223(%rip), %rsi     # 0x8e480
leaq 0x3c274(%rip), %rdx     # 0x8e4d8
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
je 0x52dc1
movq 0x60(%rax), %rax
movq %rax, 0x60(%rsp)
movq 0x130(%rsp), %rdi
movq %r13, %rsi
callq 0x49760
testq %rax, %rax
je 0x529d5
movl $0x7, 0x28(%rsp)
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
movabsq $0xffffffff0, %rcx      # imm = 0xFFFFFFFF0
testq %rcx, %rax
je 0x522e9
xorl %r14d, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r13, %rsi
callq 0x54786
incl %r14d
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
shrq $0x4, %rax
cmpl %eax, %r14d
jb 0x522b8
leaq 0x198(%rsp), %rdi
movq %rbx, %rsi
callq 0x5308a
jmp 0x525fd
movl $0x4, 0x28(%rsp)
jmp 0x52324
movl $0x2, 0x28(%rsp)
jmp 0x52324
movl $0x3, 0x28(%rsp)
jmp 0x52324
movl $0x1, 0x28(%rsp)
movq %rbx, %rdi
xorl %esi, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0x54786
movq %rbx, %rdi
movl $0x1, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0x54786
leaq 0x198(%rsp), %rdi
movq %rbx, %rsi
callq 0x5308a
jmp 0x525fd
movq %r14, %rdi
movq %r13, %rsi
leaq 0x3c3ff(%rip), %rdx     # 0x8e780
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
je 0x52527
movq %rax, %r15
movl $0x8, 0x28(%rsp)
movq 0x50(%rax), %rcx
subq 0x48(%rax), %rcx
leaq 0x28(%rsp), %rax
movabsq $0xffffffff0, %rdx      # imm = 0xFFFFFFFF0
testq %rdx, %rcx
leaq 0x60(%rsp), %r14
je 0x523f5
xorl %ebx, %ebx
movq %r15, %rdi
movl %ebx, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r14, %rsi
callq 0x54786
incl %ebx
movq 0x50(%r15), %rax
subq 0x48(%r15), %rax
shrq $0x4, %rax
cmpl %eax, %ebx
jb 0x523bf
movq 0xf0(%rsp), %rax
movq %r15, 0x18(%rsp)
movq 0xa8(%r12), %rcx
movq %r12, 0x10(%rsp)
movq 0xb0(%r12), %rbx
movq %rax, 0x60(%rsp)
movq %rbx, %r13
movq %rcx, 0xd0(%rsp)
subq %rcx, %r13
movq %r13, %rbp
sarq $0x4, %rbp
movabsq $-0x5555555555555555, %rax # imm = 0xAAAAAAAAAAAAAAAB
imulq %rax, %rbp
sarq $0x2, %rbp
testq %rbp, %rbp
jle 0x524c4
incq %rbp
leaq -0x30(%rbx), %r14
leaq 0x60(%rsp), %r12
movq %r12, %rdi
movq %r14, %rsi
callq 0x537a4
testb %al, %al
jne 0x52636
movq %rbx, %r15
addq $-0x60, %rbx
movq %r12, %rdi
movq %rbx, %rsi
callq 0x537a4
testb %al, %al
jne 0x52633
leaq -0x90(%r15), %r14
movq %r12, %rdi
movq %r14, %rsi
callq 0x537a4
testb %al, %al
jne 0x52636
addq $-0xc0, %r15
movq %r12, %rdi
movq %r15, %rsi
callq 0x537a4
testb %al, %al
jne 0x526c0
movq %r15, %rbx
addq $-0xc0, %r13
decq %rbp
cmpq $0x1, %rbp
jg 0x52447
sarq $0x4, %r13
movabsq $-0x5555555555555555, %rax # imm = 0xAAAAAAAAAAAAAAAB
imulq %rax, %r13
cmpq $0x1, %r13
je 0x52673
cmpq $0x2, %r13
leaq 0x60(%rsp), %r15
je 0x52646
cmpq $0x3, %r13
movq 0x18(%rsp), %rbp
jne 0x526a9
leaq -0x30(%rbx), %r14
movq %r15, %rdi
movq %r14, %rsi
callq 0x537a4
testb %al, %al
leaq 0xb8(%rsp), %r13
movq 0x10(%rsp), %r12
je 0x5265b
jmp 0x526da
movq %r14, %rdi
movq %r13, %rsi
leaq 0x3c28c(%rip), %rdx     # 0x8e7c0
xorl %ecx, %ecx
callq 0x8320
testq %rax, %rax
movq 0x50(%rsp), %r15
je 0x525f4
movq %rax, %rbx
movl $0x8, 0x28(%rsp)
movq 0x50(%rax), %rax
subq 0x48(%rbx), %rax
movabsq $0xffffffff0, %rcx      # imm = 0xFFFFFFFF0
addq $-0x10, %rcx
testq %rcx, %rax
leaq 0x60(%rsp), %r13
je 0x525ab
movl $0x1, %r14d
movq %rbx, %rdi
movl %r14d, %esi
callq 0x335d4
movq %rax, 0x60(%rsp)
leaq 0x30(%rsp), %rdi
movq %r13, %rsi
callq 0x54786
incl %r14d
movq 0x50(%rbx), %rax
subq 0x48(%rbx), %rax
shrq $0x4, %rax
cmpl %eax, %r14d
jb 0x5257a
movq %rbx, %rdi
xorl %esi, %esi
callq 0x335d4
movq %rax, %rbx
movl 0x28(%rsp), %eax
movl %eax, 0x60(%rsp)
leaq 0x68(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x53c60
movq 0x48(%rsp), %rax
movq %rax, 0x80(%rsp)
movq %rbx, 0x88(%rsp)
movq %r15, %rdi
movq %r13, %rsi
callq 0x54478
jmp 0x529be
movq (%rbp), %rax
movq %rax, 0x8(%rsp)
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x52614
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq 0xf8(%rsp), %rsi
leaq 0x28(%rsi), %rax
movq 0x8(%rsp), %rbp
cmpq %rax, %rbp
jne 0x520d2
jmp 0x52d52
movq %r14, %rbx
leaq 0xb8(%rsp), %r13
movq %r12, %r15
jmp 0x526d0
movq %rbx, %r14
leaq 0xb8(%rsp), %r13
movq 0x10(%rsp), %r12
movq 0x18(%rsp), %rbp
movq %r14, %rbx
addq $-0x30, %r14
movq %r15, %rdi
movq %r14, %rsi
callq 0x537a4
testb %al, %al
je 0x5268d
jmp 0x526da
movq %rbx, %r14
leaq 0xb8(%rsp), %r13
leaq 0x60(%rsp), %r15
movq 0x10(%rsp), %r12
movq 0x18(%rsp), %rbp
leaq -0x30(%r14), %rsi
movq %r15, %rdi
callq 0x537a4
testb %al, %al
movq 0xd0(%rsp), %rbx
cmovneq %r14, %rbx
jmp 0x526da
movq 0xd0(%rsp), %rbx
leaq 0xb8(%rsp), %r13
movq 0x10(%rsp), %r12
jmp 0x526da
movq %r14, %rbx
leaq 0xb8(%rsp), %r13
leaq 0x60(%rsp), %r15
movq 0x10(%rsp), %r12
movq 0x18(%rsp), %rbp
movq 0x50(%rsp), %rax
cmpq (%rax), %rbx
je 0x528a5
movq %rbx, 0x10(%rsp)
movq -0x10(%rbx), %rbx
movq 0x60(%rbx), %rax
movq %rax, 0x58(%rsp)
movq 0x60(%rbp), %rcx
movq %rcx, 0x20(%rsp)
leaq 0x28(%rax), %rsi
cmpq %rcx, %rax
je 0x5290d
movq %r13, %rdi
callq 0x53cfc
movq 0xb8(%rsp), %rax
cmpq %r13, %rax
je 0x52730
cmpq %rbx, 0x10(%rax)
je 0x52730
movq (%rax), %rax
jmp 0x52720
movq (%rax), %rsi
movq %r12, %rdi
movq %r13, %rdx
movq %rbp, %rcx
callq 0x5390a
testb %al, %al
je 0x529e2
movq 0x20(%rsp), %rsi
addq $0x28, %rsi
leaq 0x100(%rsp), %rbx
movq %rbx, %rdi
callq 0x53cfc
movq 0x100(%rsp), %rsi
movq %rsi, %rdx
cmpq %rbx, %rsi
movq %r15, %rbx
je 0x5278e
movq %rsi, %rdx
cmpq %rbp, 0x10(%rdx)
je 0x5278e
movq (%rdx), %rdx
leaq 0x100(%rsp), %rax
cmpq %rax, %rdx
jne 0x52778
movq %r12, %rdi
movq %rbp, %rcx
callq 0x5390a
testb %al, %al
je 0x529ea
leaq 0x260(%rsp), %rax
movq %rax, 0x230(%rsp)
movl $0x1, %ecx
movq %rcx, 0x238(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, %edx       # imm = 0x3F800000
movl %edx, 0x250(%rsp)
movups %xmm0, -0x8(%rax)
leaq 0x228(%rsp), %rax
movq %rax, 0x1f8(%rsp)
movq %rcx, 0x200(%rsp)
movups %xmm0, -0x20(%rax)
movl %edx, 0x218(%rsp)
movups %xmm0, -0x8(%rax)
movaps %xmm0, 0xa0(%rsp)
movaps %xmm0, 0x90(%rsp)
movaps %xmm0, 0x80(%rsp)
movaps %xmm0, 0x70(%rsp)
movaps %xmm0, 0x60(%rsp)
movq %rbx, %rdi
xorl %esi, %esi
callq 0x54020
leaq 0x1f0(%rsp), %rax
movq %rax, 0x1c0(%rsp)
movq $0x1, 0x1c8(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, 0x1e0(%rsp) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq %rbx, 0x188(%rsp)
leaq 0x1c0(%rsp), %rax
movq %rax, 0x190(%rsp)
movq 0x90(%rsp), %rax
movq 0xa0(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x529f2
movq 0x58(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x90(%rsp)
jmp 0x529ff
movl 0x28(%rsp), %eax
movl %eax, 0x60(%rsp)
leaq 0x68(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x53c60
movq 0x48(%rsp), %rax
movq %rax, 0x80(%rsp)
movq %rbp, 0x88(%rsp)
movq 0x50(%rsp), %rdi
movq %rdi, %rbx
movq %r15, %rsi
callq 0x54478
movq 0x68(%rsp), %rdi
testq %rdi, %rdi
je 0x528f8
movq 0x78(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq 0x8(%rsp), %rax
movq (%rax), %rax
movq %rax, 0x8(%rsp)
movq %rbx, %r15
jmp 0x525fd
movq %r15, %rdi
callq 0x53cfc
movq 0x60(%rsp), %rax
cmpq %r15, %rax
je 0x5292a
cmpq %rbx, 0x10(%rax)
je 0x5292a
movq (%rax), %rax
jmp 0x5291a
movq (%rax), %rsi
movq %rsi, %rdx
movq %r15, %rbx
cmpq %r15, %rsi
je 0x52949
movq %rsi, %rdx
cmpq %rbp, 0x10(%rdx)
je 0x52949
movq (%rdx), %rdx
cmpq %rbx, %rdx
jne 0x5293b
movq %r12, %rdi
movq %rbp, %rcx
callq 0x5390a
movl %eax, %r14d
movq 0x60(%rsp), %rdi
cmpq %rbx, %rdi
je 0x52979
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %r15, %rbx
movq %r15, %rbx
jne 0x52961
testb %r14b, %r14b
jne 0x52cea
movl 0x28(%rsp), %eax
movl %eax, 0x60(%rsp)
leaq 0x68(%rsp), %rdi
leaq 0x30(%rsp), %rsi
callq 0x53c60
movq 0x48(%rsp), %rax
movq %rax, 0x80(%rsp)
movq %rbp, 0x88(%rsp)
movq 0x50(%rsp), %r15
movq %r15, %rdi
movq %rbx, %rsi
callq 0x54478
movq 0x68(%rsp), %rdi
testq %rdi, %rdi
je 0x529d5
movq 0x78(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq 0x8(%rsp), %rax
movq (%rax), %rax
jmp 0x525f8
xorl %r14d, %r14d
jmp 0x52cbc
xorl %r14d, %r14d
jmp 0x52c88
movq %rbx, %rdi
leaq 0x58(%rsp), %rsi
callq 0x54196
leaq 0x1c0(%rsp), %rdi
movq %rdi, 0x150(%rsp)
leaq 0x58(%rsp), %rsi
leaq 0x150(%rsp), %rdx
callq 0x36494
leaq 0x188(%rsp), %rdi
leaq 0x230(%rsp), %rsi
movl $0x1, %edx
callq 0x53ab8
movq 0x90(%rsp), %rax
movq 0xa0(%rsp), %rcx
addq $-0x8, %rcx
cmpq %rcx, %rax
je 0x52a67
movq 0x20(%rsp), %rcx
movq %rcx, (%rax)
addq $0x8, 0x90(%rsp)
jmp 0x52a74
movq %rbx, %rdi
leaq 0x20(%rsp), %rsi
callq 0x54196
leaq 0x1c0(%rsp), %rdi
movq %rdi, 0x150(%rsp)
leaq 0x20(%rsp), %rsi
leaq 0x150(%rsp), %rdx
callq 0x36494
leaq 0x188(%rsp), %rdi
leaq 0x1f8(%rsp), %rsi
xorl %edx, %edx
callq 0x53ab8
leaq 0x180(%rsp), %rax
movq %rax, 0x150(%rsp)
movq $0x1, 0x158(%rsp)
xorps %xmm0, %xmm0
movups %xmm0, -0x20(%rax)
movl $0x3f800000, 0x170(%rsp) # imm = 0x3F800000
movups %xmm0, -0x8(%rax)
movq 0x240(%rsp), %rbx
testq %rbx, %rbx
je 0x52b74
movq 0x8(%rbx), %rcx
movq %rcx, 0x148(%rsp)
movq 0x1f8(%rsp), %rdi
movq 0x200(%rsp), %r8
movq %rcx, %rax
xorl %edx, %edx
divq %r8
movq (%rdi,%rdx,8), %rax
testq %rax, %rax
je 0x52b6c
movq %rdx, %rsi
movq (%rax), %r9
cmpq 0x8(%r9), %rcx
je 0x52b47
movq (%r9), %r9
testq %r9, %r9
je 0x52b6c
movq 0x8(%r9), %rdi
movq %rdi, %rax
xorl %edx, %edx
divq %r8
cmpq %rsi, %rdx
jne 0x52b6c
cmpq %rdi, %rcx
jne 0x52b29
leaq 0x150(%rsp), %rdi
movq %rdi, 0x118(%rsp)
leaq 0x148(%rsp), %rsi
leaq 0x118(%rsp), %rdx
callq 0x36494
movq (%rbx), %rbx
jmp 0x52ae7
movq 0xd8(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x53e7e
testq %rax, %rax
jne 0x52b9d
leaq 0x150(%rsp), %rdi
leaq 0x58(%rsp), %rsi
callq 0x53d8e
movq 0xd8(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x53e7e
testq %rax, %rax
jne 0x52bc6
leaq 0x150(%rsp), %rdi
leaq 0x20(%rsp), %rsi
callq 0x53d8e
movq 0x160(%rsp), %rbx
testq %rbx, %rbx
je 0x52c3f
movq 0x8(%rbx), %rsi
addq $0x28, %rsi
leaq 0x118(%rsp), %rbp
movq %rbp, %rdi
callq 0x53cfc
movq 0x118(%rsp), %rsi
movq %r12, %rdi
movq %rbp, %rdx
movq 0x18(%rsp), %rcx
callq 0x5390a
movl %eax, %r14d
movq 0x118(%rsp), %rdi
cmpq %rbp, %rdi
je 0x52c28
movq (%rdi), %r13
movl $0x18, %esi
callq 0x82a0
movq %r13, %rdi
cmpq %rbp, %r13
jne 0x52c13
testb %r14b, %r14b
je 0x52c44
movq (%rbx), %rbx
testq %rbx, %rbx
leaq 0xb8(%rsp), %r13
jne 0x52bd3
jmp 0x52c4c
movb $0x1, %r14b
jmp 0x52c4c
leaq 0xb8(%rsp), %r13
leaq 0x150(%rsp), %rdi
callq 0x36424
leaq 0x1c0(%rsp), %rdi
callq 0x36424
movq %r15, %rdi
callq 0x53bb8
leaq 0x1f8(%rsp), %rdi
callq 0x36424
leaq 0x230(%rsp), %rdi
callq 0x36424
movq 0x100(%rsp), %rdi
leaq 0x100(%rsp), %rbp
cmpq %rbp, %rdi
je 0x52cb2
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %rbp, %rbx
jne 0x52c9d
leaq 0x60(%rsp), %r15
movq 0x18(%rsp), %rbp
movq 0xb8(%rsp), %rdi
cmpq %r13, %rdi
je 0x52cde
movq (%rdi), %rbx
movl $0x18, %esi
callq 0x82a0
movq %rbx, %rdi
cmpq %r13, %rbx
jne 0x52cc9
testb %r14b, %r14b
movq %r15, %rbx
je 0x52982
movq 0x10(%rsp), %rax
movq -0x8(%rax), %rsi
incl 0x3c9eb(%rip)           # 0x8f6e4
movq %rbp, %rdi
callq 0x333d0
movq 0xe0(%rsp), %rax
movq 0xe8(%rsp), %rcx
movq (%rax), %rax
movq (%rcx), %rbx
movq (%rbx), %r14
decq 0x38(%rax)
movq %rbx, %rdi
callq 0x84d0
movl $0x18, %esi
movq %rbx, %rdi
callq 0x82a0
movq 0xe8(%rsp), %rax
movq %r14, (%rax)
movq (%rbp), %rax
movq %rbp, %rdi
callq *0x8(%rax)
movq 0x50(%rsp), %r15
jmp 0x525fd
movq 0x78(%rsi), %rbx
movq 0x80(%rsi), %r14
cmpq %r14, %rbx
je 0x52d73
movq (%rbx), %rsi
movq %r12, %rdi
callq 0x5205c
addq $0x8, %rbx
jmp 0x52d5d
movq 0x140(%rsp), %rax
subq 0x138(%rsp), %rax
shrq $0x4, %rax
imull $0xaaaaaaab, %eax, %eax # imm = 0xAAAAAAAB
cltq
leaq (%rax,%rax,2), %rsi
shlq $0x4, %rsi
addq 0xa8(%r12), %rsi
movq 0xb0(%r12), %rdx
movq %r15, %rdi
callq 0x548de
addq $0x268, %rsp            # imm = 0x268
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x3c220(%rip), %rdi     # 0x8efe8
leaq 0x1b399(%rip), %rsi     # 0x6e168
movl $0x8, %edx
callq 0x8330
movq 0x3c208(%rip), %rdi     # 0x8efe8
leaq 0x1eb34(%rip), %rsi     # 0x7191b
movl $0x23, %edx
callq 0x8330
movq 0x3c1f0(%rip), %rdi     # 0x8efe8
leaq 0x1c5c1(%rip), %rsi     # 0x6f3c0
movl $0x1, %edx
callq 0x8330
movq 0x3c1d8(%rip), %rdi     # 0x8efe8
movl $0xc1, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
jmp 0x52eeb
movq 0x3c1ba(%rip), %rdi     # 0x8efe8
leaq 0x1b333(%rip), %rsi     # 0x6e168
movl $0x8, %edx
callq 0x8330
movq 0x3c1a2(%rip), %rdi     # 0x8efe8
leaq 0x1eace(%rip), %rsi     # 0x7191b
movl $0x23, %edx
callq 0x8330
movq 0x3c18a(%rip), %rdi     # 0x8efe8
leaq 0x1c55b(%rip), %rsi     # 0x6f3c0
movl $0x1, %edx
callq 0x8330
movq 0x3c172(%rip), %rdi     # 0x8efe8
movl $0xa5, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
jmp 0x52eeb
movq 0x3c157(%rip), %rdi     # 0x8efe8
leaq 0x1b2d0(%rip), %rsi     # 0x6e168
movl $0x8, %edx
callq 0x8330
movq 0x3c13f(%rip), %rdi     # 0x8efe8
leaq 0x1ea6b(%rip), %rsi     # 0x7191b
movl $0x23, %edx
callq 0x8330
movq 0x3c127(%rip), %rdi     # 0x8efe8
leaq 0x1c4f8(%rip), %rsi     # 0x6f3c0
movl $0x1, %edx
callq 0x8330
movq 0x3c10f(%rip), %rdi     # 0x8efe8
movl $0xb7, %esi
callq 0x8520
movq %rax, %rdi
callq 0x8180
movl $0xff, %edi
callq 0x8380
movq %rax, %rbx
jmp 0x52fd7
movq %rax, %rbx
jmp 0x52ff1
jmp 0x52f68
movq %rbx, %r15
movq %rax, %rbx
movq 0x60(%rsp), %rdi
cmpq %r15, %rdi
je 0x5306a
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x52f1b
jmp 0x5306a
jmp 0x52fb0
jmp 0x52f40
jmp 0x53067
jmp 0x52f40
movq %rax, %rbx
movq 0x68(%rsp), %rdi
testq %rdi, %rdi
je 0x5306a
movq 0x78(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
jmp 0x5306a
jmp 0x53067
movq %rax, %rbx
jmp 0x53023
movq %rax, %rbx
jmp 0x52fc0
jmp 0x52fb0
jmp 0x53067
jmp 0x53067
movq %rax, %rbx
movq 0x118(%rsp), %rdi
cmpq %rbp, %rdi
je 0x52fb3
leaq 0x118(%rsp), %r15
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x52f99
jmp 0x52fb3
movq %rax, %rbx
leaq 0x150(%rsp), %rdi
callq 0x36424
leaq 0x1c0(%rsp), %rdi
callq 0x36424
leaq 0x60(%rsp), %rdi
callq 0x53bb8
leaq 0x1f8(%rsp), %rdi
callq 0x36424
leaq 0x230(%rsp), %rdi
callq 0x36424
movq 0x100(%rsp), %rdi
leaq 0x100(%rsp), %rax
cmpq %rax, %rdi
je 0x53023
leaq 0x100(%rsp), %r15
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x5300e
movq 0xb8(%rsp), %rdi
leaq 0xb8(%rsp), %r15
cmpq %r15, %rdi
je 0x5306a
movq (%rdi), %r14
movl $0x18, %esi
callq 0x82a0
movq %r14, %rdi
cmpq %r15, %r14
jne 0x53038
jmp 0x5306a
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
jmp 0x53067
movq %rax, %rbx
movq 0x30(%rsp), %rdi
testq %rdi, %rdi
je 0x53081
movq 0x40(%rsp), %rsi
subq %rdi, %rsi
callq 0x82a0
movq %rbx, %rdi
callq 0x8540
nop