// File: /workspace/github_cpp_makefile_star2_O2/sid1607[P]avx2-merge-sort/merge_sort.cpp
// Function: merge_phase(int*, int*, int, int, int)
void merge_phase(int *a, int *out, int start, int mid, int end) {
  int i=start, j=mid+1, k=start;
  int i_end = i + mid - start + 1;
  int j_end = j + end - mid;

  auto ra = load_reg256(&a[i]);
  auto rb = load_reg256(&a[j]);

  i += SIMD_SIZE;
  j += SIMD_SIZE;

  // 8-by-8 merge
  if (mid-start+1 == SIMD_SIZE) {
    bitonic_merge(ra, rb);
    // save the smaller half
    store_reg256(&out[k], ra);
    k += SIMD_SIZE;
    // then save the larger half
    store_reg256(&out[k], rb);
    k += SIMD_SIZE;
    return;
  }

  do {
    bitonic_merge(ra, rb);
    
    // save the smaller half
    store_reg256(&out[k], ra);
    k += SIMD_SIZE;
    
    // use the larger half for the next comparison
    ra = rb;

    // select the input with the lowest value at the current pointer
    if (a[i] < a[j]) {
      rb = load_reg256(&a[i]);
      i += SIMD_SIZE;
    } else {
      rb = load_reg256(&a[j]);
      j += SIMD_SIZE;
    }
  } while (i < i_end && j < j_end);

  // merge the final pair of registers from each input
  bitonic_merge(ra, rb);
  store_reg256(&out[k], ra);
  k += SIMD_SIZE;
  ra = rb;

  // consume remaining data from a, if left
  while (i < i_end) {
    rb = load_reg256(&a[i]);
    i += SIMD_SIZE;
    bitonic_merge(ra, rb);
    store_reg256(&out[k], ra);
    k += SIMD_SIZE;
    ra = rb;
  }

  // consume remaining data from b, if left
  while (j < j_end) {
    rb = load_reg256(&a[j]);
    j += SIMD_SIZE;
    bitonic_merge(ra, rb);
    store_reg256(&out[k], ra);
    k += SIMD_SIZE;
    ra = rb;
  }

  // store the final batch
  store_reg256(&out[k], ra);
  k += SIMD_SIZE;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
andq $-0x20, %rsp
subq $0xc0, %rsp
movq %rsi, %r12
movslq %edx, %rbx
vmovaps (%rdi,%rbx,4), %ymm0
vmovaps %ymm0, 0x60(%rsp)
movslq %ecx, %rax
vmovaps 0x4(%rdi,%rax,4), %ymm0
vmovaps %ymm0, 0x20(%rsp)
movq %rax, 0xa0(%rsp)
subl %ebx, %eax
leal 0x8(%rbx), %r13d
cmpl $0x7, %eax
jne 0x23e2
leaq 0x60(%rsp), %r15
leaq 0x20(%rsp), %r14
movq %r15, %rdi
movq %r14, %rsi
vzeroupper
callq 0x2798
vmovaps (%r15), %ymm0
vmovaps %ymm0, (%r12,%rbx,4)
movslq %r13d, %rax
vmovaps (%r14), %ymm0
vmovaps %ymm0, (%r12,%rax,4)
jmp 0x259b
movq %rdi, %r14
incl %r8d
movl %r8d, 0x14(%rsp)
leal 0x9(%rcx), %esi
movq %r12, 0x58(%rsp)
leaq (%r12,%rbx,4), %r15
shlq $0x20, %rbx
movl %r13d, %r12d
movq %rcx, 0x98(%rsp)
movq %rbx, 0x18(%rsp)
leaq 0x60(%rsp), %rdi
movl %r12d, %ebx
movq %r14, %r12
movl %esi, %r14d
leaq 0x20(%rsp), %rsi
vzeroupper
callq 0x2798
movl %r14d, %esi
movq %r12, %r14
movl %ebx, %r12d
vmovaps 0x60(%rsp), %ymm0
vmovaps %ymm0, (%r15)
vmovaps 0x20(%rsp), %ymm0
vmovaps %ymm0, 0x60(%rsp)
movslq %ebx, %rax
movl (%r14,%rax,4), %edx
movslq %esi, %rcx
cmpl (%r14,%rcx,4), %edx
jl 0x2460
addl $0x8, %esi
movq %rcx, %rax
jmp 0x2464
addl $0x8, %r12d
movq 0x18(%rsp), %rbx
vmovaps (%r14,%rax,4), %ymm0
vmovaps %ymm0, 0x20(%rsp)
addl $0x8, %r13d
movabsq $0x800000000, %rax      # imm = 0x800000000
addq %rax, %rbx
movq 0x98(%rsp), %rcx
cmpl %ecx, %r12d
jg 0x24a1
addq $0x20, %r15
cmpl 0x14(%rsp), %esi
jl 0x2408
movl %esi, 0x18(%rsp)
leaq 0x60(%rsp), %r15
leaq 0x20(%rsp), %rsi
movq %r15, %rdi
vzeroupper
callq 0x2798
sarq $0x1e, %rbx
vmovaps (%r15), %ymm0
movq 0x58(%rsp), %rax
vmovaps %ymm0, (%rax,%rbx)
movslq %r12d, %rbx
movslq %r13d, %r13
leaq (%rax,%r13,4), %r12
shlq $0x20, %r13
vmovaps 0x20(%rsp), %ymm0
vmovaps %ymm0, 0x60(%rsp)
cmpq 0xa0(%rsp), %rbx
jg 0x2530
vmovaps (%r14,%rbx,4), %ymm0
vmovaps %ymm0, 0x20(%rsp)
addq $0x8, %rbx
movq %r15, %rdi
leaq 0x20(%rsp), %rsi
vzeroupper
callq 0x2798
vmovaps 0x60(%rsp), %ymm0
vmovaps %ymm0, (%r12)
movabsq $0x800000000, %rax      # imm = 0x800000000
addq %rax, %r13
addq $0x20, %r12
jmp 0x24db
movslq 0x18(%rsp), %rbx
movslq 0x14(%rsp), %r15
cmpq %r15, %rbx
jge 0x258c
vmovaps (%r14,%rbx,4), %ymm0
vmovaps %ymm0, 0x20(%rsp)
addq $0x8, %rbx
leaq 0x60(%rsp), %rdi
leaq 0x20(%rsp), %rsi
vzeroupper
callq 0x2798
vmovaps 0x60(%rsp), %ymm0
vmovaps %ymm0, (%r12)
vmovaps 0x20(%rsp), %ymm0
vmovaps %ymm0, 0x60(%rsp)
movabsq $0x800000000, %rax      # imm = 0x800000000
addq %rax, %r13
addq $0x20, %r12
jmp 0x253a
sarq $0x1e, %r13
movq 0x58(%rsp), %rax
vmovaps %ymm0, (%rax,%r13)
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
vzeroupper
retq