// File: ATOMIC-LICHESS[P]ATOMKRAFT/thread.cpp
// Function: void ThreadsManager::split<false>(Position&, SearchStack*, Value*, Value, Value*, Depth, Move, int, MovePicker*, bool)
void ThreadsManager::split(Position& pos, SearchStack* ss, Value* alpha, const Value beta,
                           Value* bestValue, Depth depth, Move threatMove,
                           int moveCount, MovePicker* mp, bool pvNode) {
  assert(pos.is_ok());
  assert(*bestValue >= -VALUE_INFINITE);
  assert(*bestValue <= *alpha);
  assert(*alpha < beta);
  assert(beta <= VALUE_INFINITE);
  assert(depth > DEPTH_ZERO);
  assert(pos.thread() >= 0 && pos.thread() < activeThreads);
  assert(activeThreads > 1);

  int i, master = pos.thread();
  Thread& masterThread = threads[master];

  lock_grab(&mpLock);

  // If no other thread is available to help us, or if we have too many
  // active split points, don't split.
  if (   !available_slave_exists(master)
      || masterThread.activeSplitPoints >= MAX_ACTIVE_SPLIT_POINTS)
  {
      lock_release(&mpLock);
      return;
  }

  // Pick the next available split point object from the split point stack
  SplitPoint& splitPoint = masterThread.splitPoints[masterThread.activeSplitPoints++];

  // Initialize the split point object
  splitPoint.parent = masterThread.splitPoint;
  splitPoint.master = master;
  splitPoint.is_betaCutoff = false;
  splitPoint.depth = depth;
  splitPoint.threatMove = threatMove;
  splitPoint.alpha = *alpha;
  splitPoint.beta = beta;
  splitPoint.pvNode = pvNode;
  splitPoint.bestValue = *bestValue;
  splitPoint.mp = mp;
  splitPoint.moveCount = moveCount;
  splitPoint.pos = &pos;
  splitPoint.nodes = 0;
  splitPoint.ss = ss;
  for (i = 0; i < activeThreads; i++)
      splitPoint.is_slave[i] = false;

  masterThread.splitPoint = &splitPoint;

  // If we are here it means we are not available
  assert(masterThread.state != Thread::AVAILABLE);

  int workersCnt = 1; // At least the master is included

  // Allocate available threads setting state to THREAD_BOOKED
  for (i = 0; !Fake && i < activeThreads && workersCnt < maxThreadsPerSplitPoint; i++)
      if (i != master && threads[i].is_available_to(master))
      {
          threads[i].state = Thread::BOOKED;
          threads[i].splitPoint = &splitPoint;
          splitPoint.is_slave[i] = true;
          workersCnt++;
      }

  assert(Fake || workersCnt > 1);

  // We can release the lock because slave threads are already booked and master is not available
  lock_release(&mpLock);

  // Tell the threads that they have work to do. This will make them leave
  // their idle loop.
  for (i = 0; i < activeThreads; i++)
      if (i == master || splitPoint.is_slave[i])
      {
          assert(i == master || threads[i].state == Thread::BOOKED);

          threads[i].state = Thread::WORKISWAITING; // This makes the slave to exit from idle_loop()

          if (useSleepingThreads && i != master)
              threads[i].wake_up();
      }

  // Everything is set up. The master thread enters the idle loop, from
  // which it will instantly launch a search, because its state is
  // THREAD_WORKISWAITING.  We send the split point as a second parameter to the
  // idle loop, which means that the main thread will return from the idle
  // loop when all threads have finished their work at this split point.
  idle_loop(master, &splitPoint);

  // We have returned from the idle loop, which means that all threads are
  // finished. Update alpha and bestValue, and return.
  lock_grab(&mpLock);

  *alpha = splitPoint.alpha;
  *bestValue = splitPoint.bestValue;
  masterThread.activeSplitPoints--;
  masterThread.splitPoint = splitPoint.parent;
  pos.set_nodes_searched(pos.nodes_searched() + splitPoint.nodes);

  lock_release(&mpLock);
}

// Assembly:
subq $0x78, %rsp
movb 0xa0(%rsp), %al
movq 0x98(%rsp), %r10
movl 0x90(%rsp), %r10d
movl 0x88(%rsp), %r10d
movl 0x80(%rsp), %r10d
movq %rdi, 0x70(%rsp)
movq %rsi, 0x68(%rsp)
movq %rdx, 0x60(%rsp)
movq %rcx, 0x58(%rsp)
movl %r8d, 0x54(%rsp)
movq %r9, 0x48(%rsp)
andb $0x1, %al
movb %al, 0x47(%rsp)
movq 0x70(%rsp), %rax
movq %rax, 0x18(%rsp)
movq 0x68(%rsp), %rdi
callq 0x297f0
movq 0x18(%rsp), %rdi
movl %eax, 0x3c(%rsp)
movq %rdi, %rax
addq $0x40, %rax
movslq 0x3c(%rsp), %rcx
imulq $0x560, %rcx, %rcx      # imm = 0x560
addq %rcx, %rax
movq %rax, 0x30(%rsp)
callq 0x6790
movq 0x18(%rsp), %rdi
movl 0x3c(%rsp), %esi
callq 0x4fce0
testb $0x1, %al
jne 0x4ffb0
jmp 0x4ffc0
movq 0x30(%rsp), %rax
movl 0x98(%rax), %eax
cmpl $0x8, %eax
jl 0x4ffcf
movq 0x18(%rsp), %rdi
callq 0x6390
jmp 0x50337
movq 0x30(%rsp), %rax
addq $0xa0, %rax
movq 0x30(%rsp), %rdx
movl 0x98(%rdx), %ecx
movl %ecx, %esi
addl $0x1, %esi
movl %esi, 0x98(%rdx)
movslq %ecx, %rcx
imulq $0x98, %rcx, %rcx
addq %rcx, %rax
movq %rax, 0x28(%rsp)
movq 0x30(%rsp), %rax
movq 0x90(%rax), %rcx
movq 0x28(%rsp), %rax
movq %rcx, (%rax)
movl 0x3c(%rsp), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x20(%rax)
movq 0x28(%rsp), %rax
movb $0x0, 0x74(%rax)
movl 0x80(%rsp), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x10(%rax)
movl 0x88(%rsp), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x24(%rax)
movq 0x58(%rsp), %rax
movl (%rax), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x68(%rax)
movl 0x54(%rsp), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x18(%rax)
movb 0x47(%rsp), %cl
movq 0x28(%rsp), %rax
andb $0x1, %cl
movb %cl, 0x14(%rax)
movq 0x48(%rsp), %rax
movl (%rax), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x6c(%rax)
movq 0x98(%rsp), %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x28(%rax)
movl 0x90(%rsp), %ecx
movq 0x28(%rsp), %rax
movl %ecx, 0x70(%rax)
movq 0x68(%rsp), %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x8(%rax)
movq 0x28(%rsp), %rax
movq $0x0, 0x60(%rax)
movq 0x60(%rsp), %rcx
movq 0x28(%rsp), %rax
movq %rcx, 0x30(%rax)
movl $0x0, 0x40(%rsp)
movq 0x18(%rsp), %rcx
movl 0x40(%rsp), %eax
cmpl 0x34(%rcx), %eax
jge 0x500fd
movq 0x28(%rsp), %rax
movslq 0x40(%rsp), %rcx
movb $0x0, 0x75(%rax,%rcx)
movl 0x40(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x40(%rsp)
jmp 0x500d3
movq 0x28(%rsp), %rcx
movq 0x30(%rsp), %rax
movq %rcx, 0x90(%rax)
movl $0x1, 0x24(%rsp)
movl $0x0, 0x40(%rsp)
movq 0x18(%rsp), %rdx
movl 0x40(%rsp), %ecx
xorl %eax, %eax
cmpl 0x34(%rdx), %ecx
movb %al, 0x17(%rsp)
jge 0x50145
movq 0x18(%rsp), %rcx
movl 0x24(%rsp), %eax
cmpl 0x2c(%rcx), %eax
setl %al
movb %al, 0x17(%rsp)
movb 0x17(%rsp), %al
testb $0x1, %al
jne 0x50152
jmp 0x501f7
movl 0x40(%rsp), %eax
cmpl 0x3c(%rsp), %eax
je 0x501e5
movq 0x18(%rsp), %rdi
addq $0x40, %rdi
movslq 0x40(%rsp), %rax
imulq $0x560, %rax, %rax      # imm = 0x560
addq %rax, %rdi
movl 0x3c(%rsp), %esi
callq 0x4f550
testb $0x1, %al
jne 0x50187
jmp 0x501e5
movq 0x18(%rsp), %rax
movq %rax, %rcx
addq $0x40, %rcx
movslq 0x40(%rsp), %rdx
imulq $0x560, %rdx, %rdx      # imm = 0x560
addq %rdx, %rcx
movl $0x3, 0x88(%rcx)
movq 0x28(%rsp), %rcx
addq $0x40, %rax
movslq 0x40(%rsp), %rdx
imulq $0x560, %rdx, %rdx      # imm = 0x560
addq %rdx, %rax
movq %rcx, 0x90(%rax)
movq 0x28(%rsp), %rax
movslq 0x40(%rsp), %rcx
movb $0x1, 0x75(%rax,%rcx)
movl 0x24(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x24(%rsp)
jmp 0x501e7
movl 0x40(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x40(%rsp)
jmp 0x5011e
movq 0x18(%rsp), %rdi
callq 0x6390
movl $0x0, 0x40(%rsp)
movq 0x18(%rsp), %rcx
movl 0x40(%rsp), %eax
cmpl 0x34(%rcx), %eax
jge 0x5029d
movl 0x40(%rsp), %eax
cmpl 0x3c(%rsp), %eax
je 0x50237
movq 0x28(%rsp), %rax
movslq 0x40(%rsp), %rcx
movb 0x75(%rax,%rcx), %al
testb $0x1, %al
je 0x5028b
movq 0x18(%rsp), %rax
movq %rax, %rcx
addq $0x40, %rcx
movslq 0x40(%rsp), %rdx
imulq $0x560, %rdx, %rdx      # imm = 0x560
addq %rdx, %rcx
movl $0x4, 0x88(%rcx)
testb $0x1, 0x30(%rax)
je 0x50289
movl 0x40(%rsp), %eax
cmpl 0x3c(%rsp), %eax
je 0x50289
movq 0x18(%rsp), %rdi
addq $0x40, %rdi
movslq 0x40(%rsp), %rax
imulq $0x560, %rax, %rax      # imm = 0x560
addq %rax, %rdi
callq 0x4f4c0
jmp 0x5028b
jmp 0x5028d
movl 0x40(%rsp), %eax
addl $0x1, %eax
movl %eax, 0x40(%rsp)
jmp 0x50209
movq 0x18(%rsp), %rdi
movl 0x3c(%rsp), %esi
movq 0x28(%rsp), %rdx
callq 0x43370
movq 0x18(%rsp), %rdi
callq 0x6790
movq 0x28(%rsp), %rax
movl 0x68(%rax), %ecx
movq 0x58(%rsp), %rax
movl %ecx, (%rax)
movq 0x28(%rsp), %rax
movl 0x6c(%rax), %ecx
movq 0x48(%rsp), %rax
movl %ecx, (%rax)
movq 0x30(%rsp), %rax
movl 0x98(%rax), %ecx
addl $-0x1, %ecx
movl %ecx, 0x98(%rax)
movq 0x28(%rsp), %rax
movq (%rax), %rcx
movq 0x30(%rsp), %rax
movq %rcx, 0x90(%rax)
movq 0x68(%rsp), %rax
movq %rax, 0x8(%rsp)
movq 0x68(%rsp), %rdi
callq 0x2e620
movq 0x8(%rsp), %rdi
movq %rax, %rsi
movq 0x28(%rsp), %rax
movq 0x60(%rax), %rax
addq %rax, %rsi
callq 0x4e7d0
movq 0x18(%rsp), %rdi
callq 0x6390
addq $0x78, %rsp
retq
nopl (%rax)