// File: /workspace/github_c_makefile_star2_O1/felipelouza[P]egap/multiround.c
// Function: multiround
void multiround(bool hm, int group_size,char *path, g_data *input, int num_threads)
{
  customInt offset, tot_symb=0;
  // threads related
  pc_system merge;
  pthread_t t[num_threads];
  g_data buffer[Threads_buf_size];
  int e;
  
  // init threads
  if(num_threads>0) {
    pc_system_init(&merge,Threads_buf_size);
    merge.buffer = (void *) buffer;
    merge.hm = hm;
    for(int i=0;i<num_threads;i++) {
      e = pthread_create(&t[i], NULL, merger, &merge);
      if(e) die("multiround create");
    }
    if(input->verbose>0) printf("%d merger threads created\n",num_threads);
  }
  
  // multiround merging  
  for(int r=0; ;r++) {     // do as many rounds as necessary
    
    if(input->numBwt<= 2*group_size-1 ) 
       break;  // we have reached the last round (or almost)
       
    // main loop to be executed by parallel threads
    // offset is within the number of bwt
    if(num_threads>0) {
      e = pthread_mutex_lock(&merge.remutex);
      if(e) die("remaining lock 1");
      merge.remaining = (input->numBwt+group_size-1)/group_size; // parallel merges in this round
      e= pthread_mutex_unlock(&merge.remutex);
      if(e) die("remaining unlock 1");
    }
    tot_symb = 0; 
    for(offset=0; offset < input->numBwt; offset += group_size) {
      g_data g=*input; // copy current status
      if(g.verbose>2) printf("Round %d, NumBwt offset "CUSTOM_FORMAT"\n",r,offset);
      g.bws = input->bws+offset;
      g.bwtLen = input->bwtLen+offset;
      if(input->smallAlpha) g.bwtOcc = input->bwtOcc+offset;
      g.numBwt = min(group_size, input->numBwt - offset);
      g.symb_offset = tot_symb;
      g.mergeLen=0;
      for(int i=0;i<g.numBwt;i++) g.mergeLen += g.bwtLen[i];
      if(input->lcpCompute) {
        assert(!input->bwtOnly && !input->lcpMerge);
        g.bwtOnly = true;      // since this is not the last round we can only
        g.lcpCompute = false;  // compute the BWT and ignore LCP  
      }
      // prepare access to lcp values
      if(g.lcpMerge) g.lcps = input->lcps+offset;
      // execute merge, possibly using threads 
      if(num_threads>0) {
        e = sem_wait(merge.free_slots); if(e) die("multiround producer wait");
        check_g_data(&g);
        buffer[merge.pindex++ % merge.buf_size]=g; // copy g_data to buffer
        e = sem_post(merge.ready);  if(e) die("multiround producer post");
      }
      else { // no helper threads
        if (hm) holtMcMillan(&g, false);
        else gap(&g, false);
        // update input via g
        for(int i=1;i<g.numBwt;i++) {
          g.bwtLen[0] += g.bwtLen[i];
          if(g.smallAlpha)
            for(int j=0;j<g.sizeOfAlpha;j++)
              g.bwtOcc[0][j] += g.bwtOcc[i][j];
        }
        assert(g.bwtLen[0]==g.mergeLen);
      }
      // update tot_symb seen so far
      tot_symb += g.mergeLen;
    } // end of inner parallelizable loop
    assert(input->mergeLen==tot_symb);
    // --- wait till all merges for this round have been completed 
    if(num_threads>0) {
      e = pthread_mutex_lock(&merge.remutex); if(e) die("remaining lock 2");
      while(merge.remaining>0) {
        e = pthread_cond_wait(&merge.recond,&merge.remutex);
        if(e) die("remaining wait");
      }
      e = pthread_mutex_unlock(&merge.remutex); if(e) die("remaining unlock 2");
      assert(merge.pindex==merge.cindex);
      if(input->verbose>1) puts("Threads syncronized, round completed");
    }
    // merged done for all segments. merged bwt/lcp are in g.bws[0][] and g.lcps[0] (if g.lcpMerge==true)

    // update input so that it consists of fewer, larger segments. move Len and Occ real entries to the left
    for(offset=0; offset < input->numBwt; offset += group_size) {
      input->bwtLen[offset/group_size] = input->bwtLen[offset];
      input->bws[offset/group_size] = input->bws[offset];
      if(input->lcpMerge) input->lcps[offset/group_size] = input->lcps[offset];;
      // replace with a swap ??? 
      if(input->smallAlpha)
        for(int j=0;j<input->sizeOfAlpha;j++)
          input->bwtOcc[offset/group_size][j] = input->bwtOcc[offset][j];
    }
    input->numBwt = (input->numBwt+group_size-1)/group_size;
    check_g_data(input);
    if(input->verbose>0)  printf("Round %d complete: %d merged bwt/lcp saved\n",r,input->numBwt);
  } // end of all rounds except last
  if(num_threads>0) {  // last round does not use threads, kill consumers
    g_data g; // dummy task
    g.numBwt = 0;
    g.verbose = input->verbose;
    for(int i=0;i<num_threads;i++) {
        e = sem_wait(merge.free_slots); if(e) die("cleaning producer wait");
        buffer[merge.pindex++ % merge.buf_size]=g; // copy g_data to buffer
        e = sem_post(merge.ready);  if(e) die("cleaning producer post");
    }
    for(int i=0;i<num_threads;i++) {
      e = pthread_join(t[i], NULL);
      if(e) die("multiround join");
    }
    pc_system_destroy(&merge);
    if(input->verbose>1) printf("%d merge threads destroyed\n",num_threads);
  }
  // here maybe there is an additional round to go from n<2g, to g;
  // there is some code duplication, but it is an important special case 
  if(input->numBwt > group_size) { 
    offset = group_size-1; // first BWT to consider 
    tot_symb = 0;          // total number of symbols to skip
    for(int i=0;i<offset;i++)
      tot_symb += input->bwtLen[i];
    // prepare merge task  
    g_data g=*input; // copy current status
    if(g.verbose>2) printf("Special round, NumBwt offset "CUSTOM_FORMAT"\n",offset);
    g.bws = input->bws+offset;
    g.bwtLen = input->bwtLen+offset;
    if(input->smallAlpha) g.bwtOcc = input->bwtOcc+offset;
    g.numBwt = input->numBwt - offset;
    assert(g.numBwt <= group_size);
    g.symb_offset = tot_symb;
    g.mergeLen=0;
    for(int i=0;i<g.numBwt;i++) g.mergeLen += g.bwtLen[i];
    if(input->lcpCompute) {
      assert(!input->bwtOnly && !input->lcpMerge);
      g.bwtOnly = true;      // since this is not the last round we can only
      g.lcpCompute = false;  // compute the BWT and ignore LCP  
    }
    if(g.lcpMerge) g.lcps = input->lcps+offset;
    // execute merge 
    if (hm) holtMcMillan(&g, false);
    else gap(&g, false);
    // update input via g
    for(int i=1;i<g.numBwt;i++) {
      g.bwtLen[0] += g.bwtLen[i];
      if(g.smallAlpha)
        for(int j=0;j<g.sizeOfAlpha;j++)
          g.bwtOcc[0][j] += g.bwtOcc[i][j];
    }
    assert(g.bwtLen[0]==g.mergeLen);
    // update input so that it consists of fewer, larger segments. move Len and Occ real entries to the left
    input->numBwt = (input->numBwt-g.numBwt+1);
    assert(input->numBwt==group_size);
    check_g_data(input);
  }
  assert(input->numBwt <= group_size);
  // execute last round (only point where gap/hm with lastRound==true is called) 
  if (hm) holtMcMillan(input, true);
  else gap(input, true);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x6a898, %rsp          # imm = 0x6A898
movq %rcx, %rbx
movl %esi, %r12d
movl %edi, -0x30(%rbp)
movq %rsp, -0x68(%rbp)
movl %r8d, %eax
movq %rsp, %rcx
movq %rax, -0x60(%rbp)
leaq 0xf(,%rax,8), %rax
andq $-0x10, %rax
subq %rax, %rcx
movq %rcx, -0x58(%rbp)
movq %rcx, %rsp
testl %r8d, %r8d
movq %r12, -0x40(%rbp)
movl %r8d, -0x2c(%rbp)
jle 0xcdff
leaq -0x120(%rbp), %r14
movq %r14, %rdi
movl $0x14, %esi
callq 0xc9d4
leaq -0x6a8c0(%rbp), %rax
movq %rax, 0x40(%r14)
movl -0x30(%rbp), %eax
movb %al, 0xa8(%r14)
leaq -0x276(%rip), %r15      # 0xcb30
movq -0x60(%rbp), %r12
movq -0x58(%rbp), %r13
movq %r13, %rdi
xorl %esi, %esi
movq %r15, %rdx
movq %r14, %rcx
callq 0x22d0
testl %eax, %eax
je 0xcdce
leaq 0x3838(%rip), %rdi      # 0x10601
callq 0x3973
addq $0x8, %r13
decq %r12
jne 0xcdae
cmpl $0x0, 0x94(%rbx)
movq -0x40(%rbp), %r12
movl -0x2c(%rbp), %r8d
jle 0xcdff
leaq 0x3824(%rip), %rdi      # 0x10613
movl %r8d, %esi
xorl %eax, %eax
movl %r8d, %r14d
callq 0x2100
movl %r14d, %r8d
leal (%r12,%r12), %eax
movl %eax, -0x4c(%rbp)
cmpl %eax, 0x20(%rbx)
jl 0xd1e5
leaq -0xd0(%rbp), %r14
leal -0x1(%r12), %eax
movl %eax, -0x34(%rbp)
movslq %r12d, %r15
leaq (,%r15,8), %rax
movq %rax, -0x70(%rbp)
xorl %r13d, %r13d
movq %r15, -0x48(%rbp)
movl %r13d, -0x38(%rbp)
testl %r8d, %r8d
jle 0xce7d
movq %r14, %rdi
callq 0x23f0
testl %eax, %eax
je 0xce55
leaq 0x37de(%rip), %rdi      # 0x1062e
callq 0x3973
movl 0x20(%rbx), %eax
addl -0x34(%rbp), %eax
cltd
idivl %r12d
movl %eax, -0xd4(%rbp)
movq %r14, %rdi
callq 0x2240
testl %eax, %eax
je 0xce7d
leaq 0x37c7(%rip), %rdi      # 0x1063f
callq 0x3973
cmpl $0x0, 0x20(%rbx)
je 0xd0a5
xorl %r13d, %r13d
xorl %r15d, %r15d
xorl %r14d, %r14d
movl $0x5120, %edx           # imm = 0x5120
leaq -0x5240(%rbp), %rdi
movq %rbx, %rsi
callq 0x21f0
cmpl $0x3, -0x51ac(%rbp)
jl 0xcec1
leaq 0x379e(%rip), %rdi      # 0x10652
movl -0x38(%rbp), %esi
movq %r15, %rdx
xorl %eax, %eax
callq 0x2100
leaq (,%r15,8), %rax
movq (%rbx), %rcx
addq %rax, %rcx
movq %rcx, -0x5240(%rbp)
movq 0x8(%rbx), %rcx
leaq (%rcx,%r15,8), %rdx
movq %rdx, -0x5238(%rbp)
cmpb $0x1, 0x68(%rbx)
jne 0xcef9
movq 0x18(%rbx), %rdx
addq %rax, %rdx
movq %rdx, -0x5228(%rbp)
movslq 0x20(%rbx), %rdx
subq %r15, %rdx
cmpq -0x48(%rbp), %rdx
cmoval %r12d, %edx
movl %edx, -0x5220(%rbp)
movq %r14, -0x5210(%rbp)
movq $0x0, -0x5218(%rbp)
testl %edx, %edx
jle 0xcf40
movl %edx, %edx
addq %r13, %rcx
xorl %esi, %esi
xorl %edi, %edi
addq (%rcx,%rsi,8), %rdi
movq %rdi, -0x5218(%rbp)
incq %rsi
cmpq %rsi, %rdx
jne 0xcf2d
cmpb $0x0, 0x3e(%rbx)
je 0xcf54
movb $0x1, -0x5204(%rbp)
movb $0x0, -0x5202(%rbp)
cmpb $0x1, -0x5203(%rbp)
jne 0xcf6b
addq 0x88(%rbx), %rax
movq %rax, -0x51b8(%rbp)
cmpl $0x0, -0x2c(%rbp)
jle 0xcffd
movq -0xf0(%rbp), %rdi
callq 0x2080
testl %eax, %eax
je 0xcf91
leaq 0x36e3(%rip), %rdi      # 0x1066f
callq 0x3973
leaq -0x5240(%rbp), %r12
movq %r12, %rdi
callq 0x39cf
movl -0x120(%rbp), %eax
leal 0x1(%rax), %ecx
movl %ecx, -0x120(%rbp)
cltd
idivl -0xd8(%rbp)
movslq %edx, %rax
imulq $0x5120, %rax, %rax     # imm = 0x5120
leaq (%rax,%rbp), %rdi
addq $-0x6a8c0, %rdi         # imm = 0xFFF95740
movl $0x5120, %edx           # imm = 0x5120
movq %r12, %rsi
callq 0x21f0
movq -0xe8(%rbp), %rdi
callq 0x2170
testl %eax, %eax
je 0xd085
leaq 0x3695(%rip), %rdi      # 0x10688
callq 0x3973
jmp 0xd085
cmpb $0x0, -0x30(%rbp)
je 0xd013
leaq -0x5240(%rbp), %rdi
xorl %esi, %esi
callq 0xbe70
jmp 0xd021
leaq -0x5240(%rbp), %rdi
xorl %esi, %esi
callq 0xa689
movslq -0x5220(%rbp), %rax
cmpq $0x2, %rax
jl 0xd085
movq -0x5238(%rbp), %rcx
movq -0x5228(%rbp), %rdx
movl -0x5208(%rbp), %edi
testl %edi, %edi
setg %sil
andb -0x51d8(%rbp), %sil
movl %edi, %edi
movl $0x1, %r8d
movq (%rcx,%r8,8), %r9
addq %r9, (%rcx)
testb %sil, %sil
je 0xd07d
movq (%rdx,%r8,8), %r9
movq (%rdx), %r10
xorl %r11d, %r11d
movq (%r9,%r11,8), %r12
addq %r12, (%r10,%r11,8)
incq %r11
cmpq %r11, %rdi
jne 0xd06d
incq %r8
cmpq %rax, %r8
jne 0xd057
addq -0x5218(%rbp), %r14
addq -0x48(%rbp), %r15
movslq 0x20(%rbx), %rax
addq -0x70(%rbp), %r13
cmpq %rax, %r15
movq -0x40(%rbp), %r12
jb 0xce90
cmpl $0x0, -0x2c(%rbp)
leaq -0xd0(%rbp), %r14
movq -0x48(%rbp), %r15
jle 0xd122
movq %r14, %rdi
callq 0x23f0
testl %eax, %eax
je 0xd0cb
leaq 0x35d8(%rip), %rdi      # 0x106a1
jmp 0xd0ee
cmpl $0x0, -0xd4(%rbp)
jle 0xd0f5
leaq -0xa8(%rbp), %rdi
movq %r14, %rsi
callq 0x20c0
testl %eax, %eax
je 0xd0cb
leaq 0x35c4(%rip), %rdi      # 0x106b2
callq 0x3973
jmp 0xd0cb
movq %r14, %rdi
callq 0x2240
testl %eax, %eax
je 0xd10d
leaq 0x35b9(%rip), %rdi      # 0x106c1
callq 0x3973
cmpl $0x2, 0x94(%rbx)
jl 0xd122
leaq 0x35b7(%rip), %rdi      # 0x106d4
callq 0x2090
movslq 0x20(%rbx), %rcx
testq %rcx, %rcx
je 0xd19d
movb 0x3d(%rbx), %dil
movb 0x68(%rbx), %r8b
xorl %esi, %esi
movq 0x8(%rbx), %r9
movq (%r9,%rsi,8), %r10
movq %rsi, %rax
xorl %edx, %edx
divq %r15
movq %r10, (%r9,%rax,8)
movq (%rbx), %rdx
movq (%rdx,%rsi,8), %r9
movq %r9, (%rdx,%rax,8)
testb %dil, %dil
je 0xd168
movq 0x88(%rbx), %rdx
movq (%rdx,%rsi,8), %r9
movq %r9, (%rdx,%rax,8)
testb %r8b, %r8b
je 0xd195
movslq 0x38(%rbx), %rdx
testq %rdx, %rdx
jle 0xd195
movq 0x18(%rbx), %r10
movq (%r10,%rsi,8), %r9
movq (%r10,%rax,8), %rax
xorl %r10d, %r10d
movq (%r9,%r10,8), %r11
movq %r11, (%rax,%r10,8)
incq %r10
cmpq %r10, %rdx
jne 0xd185
addq %r15, %rsi
cmpq %rcx, %rsi
jb 0xd135
addl -0x34(%rbp), %ecx
movl %ecx, %eax
cltd
idivl %r12d
movl %eax, 0x20(%rbx)
movq %rbx, %rdi
callq 0x39cf
cmpl $0x0, 0x94(%rbx)
movl -0x38(%rbp), %r13d
jle 0xd1d2
movl 0x20(%rbx), %edx
leaq 0x3531(%rip), %rdi      # 0x106f9
movl %r13d, %esi
xorl %eax, %eax
callq 0x2100
incl %r13d
movl -0x4c(%rbp), %eax
cmpl %eax, 0x20(%rbx)
movl -0x2c(%rbp), %r8d
jge 0xce34
testl %r8d, %r8d
jle 0xd2ca
movl 0x94(%rbx), %r12d
leaq 0x3540(%rip), %r14      # 0x1073c
leaq 0x3522(%rip), %r15      # 0x10725
movl %r8d, %r13d
movq -0xf0(%rbp), %rdi
callq 0x2080
testl %eax, %eax
je 0xd21e
movq %r15, %rdi
callq 0x3973
movl -0x120(%rbp), %eax
leal 0x1(%rax), %ecx
movl %ecx, -0x120(%rbp)
cltd
idivl -0xd8(%rbp)
movslq %edx, %rax
imulq $0x5120, %rax, %rax     # imm = 0x5120
movl $0x0, -0x6a8a0(%rbp,%rax)
movl %r12d, -0x6a82c(%rbp,%rax)
movq -0xe8(%rbp), %rdi
callq 0x2170
testl %eax, %eax
je 0xd269
movq %r14, %rdi
callq 0x3973
decl %r13d
jne 0xd206
xorl %r15d, %r15d
leaq 0x34db(%rip), %r14      # 0x10753
movq -0x40(%rbp), %r12
movl -0x2c(%rbp), %r13d
movq -0x58(%rbp), %rax
movq (%rax,%r15,8), %rdi
xorl %esi, %esi
callq 0x23a0
testl %eax, %eax
je 0xd29b
movq %r14, %rdi
callq 0x3973
incq %r15
cmpq %r15, -0x60(%rbp)
jne 0xd280
leaq -0x120(%rbp), %rdi
callq 0xcac0
cmpl $0x1, 0x94(%rbx)
jle 0xd2ca
leaq 0x34a3(%rip), %rdi      # 0x10763
movl %r13d, %esi
xorl %eax, %eax
callq 0x2100
cmpl %r12d, 0x20(%rbx)
jle 0xd464
decl %r12d
je 0xd2f6
movq 0x8(%rbx), %rax
movq %r12, %r13
movl %r12d, %ecx
xorl %edx, %edx
xorl %r12d, %r12d
addq (%rax,%rdx,8), %r12
incq %rdx
cmpq %rdx, %rcx
jne 0xd2e8
jmp 0xd2fc
movq %r12, %r13
xorl %r12d, %r12d
movslq %r13d, %r14
leaq -0x5240(%rbp), %r15
movl $0x5120, %edx           # imm = 0x5120
movq %r15, %rdi
movq %rbx, %rsi
callq 0x21f0
cmpl $0x2, 0x94(%r15)
jle 0xd331
leaq 0x3458(%rip), %rdi      # 0x1077f
movq %r14, %rsi
xorl %eax, %eax
callq 0x2100
shlq $0x3, %r14
movq (%rbx), %rax
addq %r14, %rax
movq %rax, -0x5240(%rbp)
movq 0x8(%rbx), %rax
addq %r14, %rax
movq %rax, -0x5238(%rbp)
cmpb $0x1, 0x68(%rbx)
jne 0xd364
movq 0x18(%rbx), %rcx
addq %r14, %rcx
movq %rcx, -0x5228(%rbp)
movl 0x20(%rbx), %ecx
subl %r13d, %ecx
movl %ecx, -0x5220(%rbp)
movq %r12, -0x5210(%rbp)
movq $0x0, -0x5218(%rbp)
testl %ecx, %ecx
jle 0xd39f
movl %ecx, %ecx
xorl %edx, %edx
xorl %esi, %esi
addq (%rax,%rdx,8), %rsi
movq %rsi, -0x5218(%rbp)
incq %rdx
cmpq %rdx, %rcx
jne 0xd38c
cmpb $0x0, 0x3e(%rbx)
je 0xd3b3
movb $0x1, -0x5204(%rbp)
movb $0x0, -0x5202(%rbp)
cmpb $0x1, -0x5203(%rbp)
jne 0xd3ca
addq 0x88(%rbx), %r14
movq %r14, -0x51b8(%rbp)
cmpb $0x0, -0x30(%rbp)
je 0xd3e0
leaq -0x5240(%rbp), %rdi
xorl %esi, %esi
callq 0xbe70
jmp 0xd3ee
leaq -0x5240(%rbp), %rdi
xorl %esi, %esi
callq 0xa689
movslq -0x5220(%rbp), %rax
cmpq $0x2, %rax
jl 0xd452
movq -0x5238(%rbp), %rcx
movq -0x5228(%rbp), %rdx
movl -0x5208(%rbp), %edi
testl %edi, %edi
setg %sil
andb -0x51d8(%rbp), %sil
movl %edi, %edi
movl $0x1, %r8d
movq (%rcx,%r8,8), %r9
addq %r9, (%rcx)
testb %sil, %sil
je 0xd44a
movq (%rdx,%r8,8), %r9
movq (%rdx), %r10
xorl %r11d, %r11d
movq (%r9,%r11,8), %r14
addq %r14, (%r10,%r11,8)
incq %r11
cmpq %r11, %rdi
jne 0xd43a
incq %r8
cmpq %rax, %r8
jne 0xd424
movl 0x20(%rbx), %ecx
subl %eax, %ecx
incl %ecx
movl %ecx, 0x20(%rbx)
movq %rbx, %rdi
callq 0x39cf
cmpb $0x0, -0x30(%rbp)
je 0xd479
movq %rbx, %rdi
movl $0x1, %esi
callq 0xbe70
jmp 0xd486
movq %rbx, %rdi
movl $0x1, %esi
callq 0xa689
movq -0x68(%rbp), %rsp
leaq -0x28(%rbp), %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq