// File: /workspace/github_c_makefile_star2_O0/felipelouza[P]egap/unbwt.c
// Function: invert_bwt
void invert_bwt(char *bnam, char *tnam)
{
  FILE *b, *t;
  uint64_t occ[_BW_ALPHA_SIZE];      // emulation of first column of bwt matrix 
  uint64_t start_sa_range[_BW_ALPHA_SIZE+1];
  uint64_t i,tot;
  uint32_t *rankprev, *bwt;
  uint8_t *high8 = NULL;

  b = fopen(bnam,"r");
  if(b==NULL) perror_die("Error opening infile");
  t = fopen(tnam,"w");
  if(t==NULL) perror_die("Error opening outfile");

  // get BWT size
  long bsize = fseek(b,0,SEEK_END);
  if(bsize<0) perror_die("fseek error");
  bsize = ftell(b);
  if(bsize<0) perror_die("ftell error");
  rewind(b);
  
  if(bsize>0xFFFFFFFFFF) 
    die("BWT too large for internal memory inversion");// maximum limit is 2^40 -1
  if(bsize>0xFFFFFFFF) {
    fprintf(stderr,"Large file (>4GB): using 5n bytes ram\n");
    // we need an extra array to store the highest 8 bits 
    high8 = malloc(bsize*sizeof(*high8));
    if(high8==NULL) die("Out of mem");
  }
  bwt = rankprev = (uint32_t *) malloc(bsize*sizeof(*rankprev));
  if(rankprev==NULL) die("Out of mem");

  // clear occ
  for(i=0;i<_BW_ALPHA_SIZE;i++) occ[i]=0;  
  // read bwt from file and compute occ
  for(i=0;i<bsize;i++) {
    int e = fread(bwt+i,1,1,b);
    if(e!=1) perror_die("Error reading BWT");
    occ[bwt[i]]++; // increment count
  }
  if(fclose(b)!=0) perror_die("Error closing BWT file");
  
  // compute start sa_range  
  for(i=0,tot=0;i<_BW_ALPHA_SIZE;i++) {
    start_sa_range[i] = tot; tot+= occ[i];
  }
  start_sa_range[_BW_ALPHA_SIZE] = tot;  
  assert(tot==bsize);

  fprintf(stderr,"Computing rankprev\n");
  // bwt -> rankprev inplace
  for(i=0;i<bsize;i++) {
      // if(i%10000==0) fprintf(stderr,"%ld outof %ld\n",i,bsize);
      uint64_t rp = (start_sa_range[bwt[i]]++);
      assert(rp<bsize);
      rankprev[i] = (uint32_t) rp;
      if(high8) high8[i]=(uint8_t)(rp>>32);
  } 
  assert(start_sa_range[_BW_ALPHA_SIZE-1]==start_sa_range[_BW_ALPHA_SIZE]);
  fprintf(stderr,"Done\n");  
  // recover the original start_sa_range values
  tot=0;
  for(i=0;i<_BW_ALPHA_SIZE;i++) {
    uint64_t temp = start_sa_range[i];
    start_sa_range[i]=tot;
    tot=temp;
  }
  assert(tot==start_sa_range[_BW_ALPHA_SIZE]);

  // start recovering of sequences
  // init buffer
  long s_size=1024; long s_step = 1024;
  char *s = malloc(s_size*sizeof(*s));
  if(!s) die("out of mem");
  long s_pos = 0;
  for(int i=0;i<occ[0];i++) {
    if(i%10000==0) fprintf(stderr,"Recovering sequecence %d\n",i);
    s_pos=0;
    long old_rank = i;
    while(true) {
      // move to first column
      uint64_t rank = rankprev[old_rank];
      if(high8!=NULL) rank += ((uint64_t) high8[old_rank]) << 32;
      int32_t c = get_char_from_first_column64(rank, start_sa_range);
      //fprintf(stderr,"%ld --> %d\n",rank,c); 
      if(c==0) break; //end of sequence
      if(s_pos>=s_size) {
        assert(s_pos==s_size);
        s_size += s_step;
        s = realloc(s,s_size*sizeof(*s));
      }
      assert(s_pos<s_size);  
      s[s_pos++] = c;
      old_rank = rank;
    }
    if(s_pos==0)
      die("Empty string in BWT file");
    // ---- reverse string ----
    for(long k=0;k<s_pos/2;k++) {
     char c = s[k]; s[k] = s[s_pos-1-k]; s[s_pos-1-k]=c;
    }
    // write string
    // fprintf(t,">\n");
    int e = fwrite(s,1,s_pos,t);
    if(e!=s_pos) perror_die("Error writing ouput sequence");
    fprintf(t,"\n");
  }
  fprintf(stderr,"Recovered %zu sequences\n",occ[0]);
  if(fclose(t)!=0) perror_die("Error closing output file");      
  free(rankprev);
  if(high8) free(high8);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x10d0, %rsp           # imm = 0x10D0
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq $0x0, -0x1058(%rbp)
movq -0x8(%rbp), %rdi
leaq 0xda6(%rip), %rsi       # 0x203f
callq 0x10d0
movq %rax, -0x18(%rbp)
cmpq $0x0, -0x18(%rbp)
jne 0x12b5
leaq 0xd58(%rip), %rdi       # 0x2008
callq 0x1250
movq -0x10(%rbp), %rdi
leaq 0xd5d(%rip), %rsi       # 0x201d
callq 0x10d0
movq %rax, -0x20(%rbp)
cmpq $0x0, -0x20(%rbp)
jne 0x12dc
leaq 0xd48(%rip), %rdi       # 0x201f
callq 0x1250
movq -0x18(%rbp), %rdi
xorl %eax, %eax
movl %eax, %esi
movl $0x2, %edx
callq 0x10b0
cltq
movq %rax, -0x1060(%rbp)
cmpq $0x0, -0x1060(%rbp)
jge 0x130d
leaq 0xd2d(%rip), %rdi       # 0x2035
callq 0x1250
movq -0x18(%rbp), %rdi
callq 0x1090
movq %rax, -0x1060(%rbp)
cmpq $0x0, -0x1060(%rbp)
jge 0x1333
leaq 0xd13(%rip), %rdi       # 0x2041
callq 0x1250
movq -0x18(%rbp), %rdi
callq 0x1060
movabsq $0xffffffffff, %rax     # imm = 0xFFFFFFFFFF
cmpq %rax, -0x1060(%rbp)
jle 0x135b
leaq 0xcf7(%rip), %rdi       # 0x204d
callq 0x1210
movl $0xffffffff, %eax       # imm = 0xFFFFFFFF
cmpq %rax, -0x1060(%rbp)
jle 0x13b0
movq 0x2c88(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0xcff(%rip), %rsi       # 0x2079
movb $0x0, %al
callq 0x1080
movq -0x1060(%rbp), %rdi
shlq $0x0, %rdi
callq 0x10a0
movq %rax, -0x1058(%rbp)
cmpq $0x0, -0x1058(%rbp)
jne 0x13ae
leaq 0xcf7(%rip), %rdi       # 0x20a0
callq 0x1210
jmp 0x13b0
movq -0x1060(%rbp), %rdi
shlq $0x2, %rdi
callq 0x10a0
movq %rax, -0x1048(%rbp)
movq %rax, -0x1050(%rbp)
cmpq $0x0, -0x1048(%rbp)
jne 0x13e4
leaq 0xcc1(%rip), %rdi       # 0x20a0
callq 0x1210
movq $0x0, -0x1038(%rbp)
cmpq $0x100, -0x1038(%rbp) # imm = 0x100
jae 0x1423
movq -0x1038(%rbp), %rax
movq $0x0, -0x820(%rbp,%rax,8)
movq -0x1038(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1038(%rbp)
jmp 0x13ef
movq $0x0, -0x1038(%rbp)
movq -0x1038(%rbp), %rax
cmpq -0x1060(%rbp), %rax
jae 0x14bb
movq -0x1050(%rbp), %rdi
movq -0x1038(%rbp), %rax
shlq $0x2, %rax
addq %rax, %rdi
movq -0x18(%rbp), %rcx
movl $0x1, %edx
movq %rdx, %rsi
callq 0x1040
movl %eax, -0x1064(%rbp)
cmpl $0x1, -0x1064(%rbp)
je 0x147f
leaq 0xc31(%rip), %rdi       # 0x20ab
callq 0x1250
movq -0x1050(%rbp), %rax
movq -0x1038(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movq -0x820(%rbp,%rax,8), %rcx
addq $0x1, %rcx
movq %rcx, -0x820(%rbp,%rax,8)
movq -0x1038(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1038(%rbp)
jmp 0x142e
movq -0x18(%rbp), %rdi
callq 0x1050
cmpl $0x0, %eax
je 0x14d5
leaq 0xbed(%rip), %rdi       # 0x20bd
callq 0x1250
movq $0x0, -0x1038(%rbp)
movq $0x0, -0x1040(%rbp)
cmpq $0x100, -0x1038(%rbp) # imm = 0x100
jae 0x153f
movq -0x1040(%rbp), %rcx
movq -0x1038(%rbp), %rax
movq %rcx, -0x1030(%rbp,%rax,8)
movq -0x1038(%rbp), %rax
movq -0x820(%rbp,%rax,8), %rax
addq -0x1040(%rbp), %rax
movq %rax, -0x1040(%rbp)
movq -0x1038(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1038(%rbp)
jmp 0x14eb
movq -0x1040(%rbp), %rax
movq %rax, -0x830(%rbp)
movq -0x1040(%rbp), %rax
cmpq -0x1060(%rbp), %rax
jne 0x155f
jmp 0x157e
leaq 0xb6e(%rip), %rdi       # 0x20d4
leaq 0xb72(%rip), %rsi       # 0x20df
movl $0x67, %edx
leaq 0xb6e(%rip), %rcx       # 0x20e7
callq 0x1070
movq 0x2a73(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0xb78(%rip), %rsi       # 0x2107
movb $0x0, %al
callq 0x1080
movq $0x0, -0x1038(%rbp)
movq -0x1038(%rbp), %rax
cmpq -0x1060(%rbp), %rax
jae 0x1672
movq -0x1050(%rbp), %rax
movq -0x1038(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movl %eax, %ecx
movq -0x1030(%rbp,%rcx,8), %rax
movq %rax, %rdx
addq $0x1, %rdx
movq %rdx, -0x1030(%rbp,%rcx,8)
movq %rax, -0x1070(%rbp)
movq -0x1070(%rbp), %rax
cmpq -0x1060(%rbp), %rax
jae 0x15f8
jmp 0x1617
leaq 0xb1c(%rip), %rdi       # 0x211b
leaq 0xad9(%rip), %rsi       # 0x20df
movl $0x6e, %edx
leaq 0xad5(%rip), %rcx       # 0x20e7
callq 0x1070
movq -0x1070(%rbp), %rax
movl %eax, %edx
movq -0x1048(%rbp), %rax
movq -0x1038(%rbp), %rcx
movl %edx, (%rax,%rcx,4)
cmpq $0x0, -0x1058(%rbp)
je 0x1659
movq -0x1070(%rbp), %rax
shrq $0x20, %rax
movb %al, %dl
movq -0x1058(%rbp), %rax
movq -0x1038(%rbp), %rcx
movb %dl, (%rax,%rcx)
jmp 0x165b
movq -0x1038(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1038(%rbp)
jmp 0x15a1
movq -0x838(%rbp), %rax
cmpq -0x830(%rbp), %rax
jne 0x1684
jmp 0x16a3
leaq 0xa99(%rip), %rdi       # 0x2124
leaq 0xa4d(%rip), %rsi       # 0x20df
movl $0x72, %edx
leaq 0xa49(%rip), %rcx       # 0x20e7
callq 0x1070
movq 0x294e(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
leaq 0xab1(%rip), %rsi       # 0x2165
movb $0x0, %al
callq 0x1080
movq $0x0, -0x1040(%rbp)
movq $0x0, -0x1038(%rbp)
cmpq $0x100, -0x1038(%rbp) # imm = 0x100
jae 0x172c
movq -0x1038(%rbp), %rax
movq -0x1030(%rbp,%rax,8), %rax
movq %rax, -0x1078(%rbp)
movq -0x1040(%rbp), %rcx
movq -0x1038(%rbp), %rax
movq %rcx, -0x1030(%rbp,%rax,8)
movq -0x1078(%rbp), %rax
movq %rax, -0x1040(%rbp)
movq -0x1038(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x1038(%rbp)
jmp 0x16d1
movq -0x1040(%rbp), %rax
cmpq -0x830(%rbp), %rax
jne 0x173e
jmp 0x175d
leaq 0xa26(%rip), %rdi       # 0x216b
leaq 0x993(%rip), %rsi       # 0x20df
movl $0x7b, %edx
leaq 0x98f(%rip), %rcx       # 0x20e7
callq 0x1070
movq $0x400, -0x1080(%rbp) # imm = 0x400
movq $0x400, -0x1088(%rbp) # imm = 0x400
movq -0x1080(%rbp), %rdi
shlq $0x0, %rdi
callq 0x10a0
movq %rax, -0x1090(%rbp)
cmpq $0x0, -0x1090(%rbp)
jne 0x17a0
leaq 0x9f4(%rip), %rdi       # 0x218f
callq 0x1210
movq $0x0, -0x1098(%rbp)
movl $0x0, -0x109c(%rbp)
movslq -0x109c(%rbp), %rax
cmpq -0x820(%rbp), %rax
jae 0x1a8f
movl -0x109c(%rbp), %eax
movl $0x2710, %ecx           # imm = 0x2710
cltd
idivl %ecx
cmpl $0x0, %edx
jne 0x17fa
movq 0x2815(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movl -0x109c(%rbp), %edx
leaq 0x9a7(%rip), %rsi       # 0x219a
movb $0x0, %al
callq 0x1080
movq $0x0, -0x1098(%rbp)
movslq -0x109c(%rbp), %rax
movq %rax, -0x10a8(%rbp)
movq -0x1048(%rbp), %rax
movq -0x10a8(%rbp), %rcx
movl (%rax,%rcx,4), %eax
movq %rax, -0x10b0(%rbp)
cmpq $0x0, -0x1058(%rbp)
je 0x1859
movq -0x1058(%rbp), %rax
movq -0x10a8(%rbp), %rcx
movzbl (%rax,%rcx), %eax
shlq $0x20, %rax
addq -0x10b0(%rbp), %rax
movq %rax, -0x10b0(%rbp)
movq -0x10b0(%rbp), %rdi
leaq -0x1030(%rbp), %rsi
callq 0x1b00
movl %eax, -0x10b4(%rbp)
cmpl $0x0, -0x10b4(%rbp)
jne 0x1880
jmp 0x195f
movq -0x1098(%rbp), %rax
cmpq -0x1080(%rbp), %rax
jl 0x18f4
movq -0x1098(%rbp), %rax
cmpq -0x1080(%rbp), %rax
jne 0x18a2
jmp 0x18c1
leaq 0x90b(%rip), %rdi       # 0x21b4
leaq 0x82f(%rip), %rsi       # 0x20df
movl $0x8f, %edx
leaq 0x82b(%rip), %rcx       # 0x20e7
callq 0x1070
movq -0x1088(%rbp), %rax
addq -0x1080(%rbp), %rax
movq %rax, -0x1080(%rbp)
movq -0x1090(%rbp), %rdi
movq -0x1080(%rbp), %rsi
shlq $0x0, %rsi
callq 0x10c0
movq %rax, -0x1090(%rbp)
movq -0x1098(%rbp), %rax
cmpq -0x1080(%rbp), %rax
jge 0x1906
jmp 0x1925
leaq 0x8b5(%rip), %rdi       # 0x21c2
leaq 0x7cb(%rip), %rsi       # 0x20df
movl $0x93, %edx
leaq 0x7c7(%rip), %rcx       # 0x20e7
callq 0x1070
movl -0x10b4(%rbp), %eax
movb %al, %dl
movq -0x1090(%rbp), %rax
movq -0x1098(%rbp), %rcx
movq %rcx, %rsi
addq $0x1, %rsi
movq %rsi, -0x1098(%rbp)
movb %dl, (%rax,%rcx)
movq -0x10b0(%rbp), %rax
movq %rax, -0x10a8(%rbp)
jmp 0x1813
cmpq $0x0, -0x1098(%rbp)
jne 0x1975
leaq 0x85f(%rip), %rdi       # 0x21cf
callq 0x1210
movq $0x0, -0x10c0(%rbp)
movq -0x10c0(%rbp), %rax
movq %rax, -0x10d0(%rbp)
movq -0x1098(%rbp), %rax
movl $0x2, %ecx
cqto
idivq %rcx
movq %rax, %rcx
movq -0x10d0(%rbp), %rax
cmpq %rcx, %rax
jge 0x1a2b
movq -0x1090(%rbp), %rax
movq -0x10c0(%rbp), %rcx
movb (%rax,%rcx), %al
movb %al, -0x10c1(%rbp)
movq -0x1090(%rbp), %rax
movq -0x1098(%rbp), %rcx
subq $0x1, %rcx
subq -0x10c0(%rbp), %rcx
movb (%rax,%rcx), %dl
movq -0x1090(%rbp), %rax
movq -0x10c0(%rbp), %rcx
movb %dl, (%rax,%rcx)
movb -0x10c1(%rbp), %dl
movq -0x1090(%rbp), %rax
movq -0x1098(%rbp), %rcx
subq $0x1, %rcx
subq -0x10c0(%rbp), %rcx
movb %dl, (%rax,%rcx)
movq -0x10c0(%rbp), %rax
addq $0x1, %rax
movq %rax, -0x10c0(%rbp)
jmp 0x1980
movq -0x1090(%rbp), %rdi
movq -0x1098(%rbp), %rdx
movq -0x20(%rbp), %rcx
movl $0x1, %esi
callq 0x1100
movl %eax, -0x10c8(%rbp)
movslq -0x10c8(%rbp), %rax
cmpq -0x1098(%rbp), %rax
je 0x1a69
leaq 0x784(%rip), %rdi       # 0x21e8
callq 0x1250
movq -0x20(%rbp), %rdi
leaq 0x7de(%rip), %rsi       # 0x2252
movb $0x0, %al
callq 0x1080
movl -0x109c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x109c(%rbp)
jmp 0x17b5
movq 0x2562(%rip), %rax      # 0x3ff8
movq (%rax), %rdi
movq -0x820(%rbp), %rdx
leaq 0x75e(%rip), %rsi       # 0x2205
movb $0x0, %al
callq 0x1080
movq -0x20(%rbp), %rdi
callq 0x1050
cmpl $0x0, %eax
je 0x1ac8
leaq 0x75b(%rip), %rdi       # 0x221e
callq 0x1250
movq -0x1048(%rbp), %rdi
callq 0x1030
cmpq $0x0, -0x1058(%rbp)
je 0x1aea
movq -0x1058(%rbp), %rdi
callq 0x1030
addq $0x10d0, %rsp           # imm = 0x10D0
popq %rbp
retq
nopw %cs:(%rax,%rax)