// File: twekkel[P]mzpq/libzpaq.cpp
// Function: libzpaq::Predictor::predict0()
int Predictor::predict0() {
  assert(initTables);
  assert(c8>=1 && c8<=255);

  // Predict next bit
  int n=z.header[6];
  assert(n>0 && n<=255);
  const U8* cp=&z.header[7];
  assert(cp[-1]==n);
  for (int i=0; i<n; ++i) {
    assert(cp>&z.header[0] && cp<&z.header[z.header.isize()-8]);
    Component& cr=comp[i];
    switch(cp[0]) {
      case CONS:  // c
        break;
      case CM:  // sizebits limit
        cr.cxt=h[i]^hmap4;
        p[i]=stretch(cr.cm(cr.cxt)>>17);
        break;
      case ICM: // sizebits
        assert((hmap4&15)>0);
        if (c8==1 || (c8&0xf0)==16) cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8);
        cr.cxt=cr.ht[cr.c+(hmap4&15)];
        p[i]=stretch(cr.cm(cr.cxt)>>8);
        break;
      case MATCH: // sizebits bufbits: a=len, b=offset, c=bit, cxt=bitpos,
                  //                   ht=buf, limit=pos
        assert(cr.cm.size()==(size_t(1)<<cp[1]));
        assert(cr.ht.size()==(size_t(1)<<cp[2]));
        assert(cr.a<=255);
        assert(cr.c==0 || cr.c==1);
        assert(cr.cxt<8);
        assert(cr.limit<cr.ht.size());
        if (cr.a==0) p[i]=0;
        else {
          cr.c=(cr.ht(cr.limit-cr.b)>>(7-cr.cxt))&1; // predicted bit
          p[i]=stretch(dt2k[cr.a]*(cr.c*-2+1)&32767);
        }
        break;
      case AVG: // j k wt
        p[i]=(p[cp[1]]*cp[3]+p[cp[2]]*(256-cp[3]))>>8;
        break;
      case MIX2: { // sizebits j k rate mask
                   // c=size cm=wt[size] cxt=input
        cr.cxt=((h[i]+(c8&cp[5]))&(cr.c-1));
        assert(cr.cxt<cr.a16.size());
        int w=cr.a16[cr.cxt];
        assert(w>=0 && w<65536);
        p[i]=(w*p[cp[2]]+(65536-w)*p[cp[3]])>>16;
        assert(p[i]>=-2048 && p[i]<2048);
      }
        break;
      case MIX: {  // sizebits j m rate mask
                   // c=size cm=wt[size][m] cxt=index of wt in cm
        int m=cp[3];
        assert(m>=1 && m<=i);
        cr.cxt=h[i]+(c8&cp[5]);
        cr.cxt=(cr.cxt&(cr.c-1))*m; // pointer to row of weights
        assert(cr.cxt<=cr.cm.size()-m);
        int* wt=(int*)&cr.cm[cr.cxt];
        p[i]=0;
        for (int j=0; j<m; ++j)
          p[i]+=(wt[j]>>8)*p[cp[2]+j];
        p[i]=clamp2k(p[i]>>8);
      }
        break;
      case ISSE: { // sizebits j -- c=hi, cxt=bh
        assert((hmap4&15)>0);
        if (c8==1 || (c8&0xf0)==16)
          cr.c=find(cr.ht, cp[1]+2, h[i]+16*c8);
        cr.cxt=cr.ht[cr.c+(hmap4&15)];  // bit history
        int *wt=(int*)&cr.cm[cr.cxt*2];
        p[i]=clamp2k((wt[0]*p[cp[2]]+wt[1]*64)>>16);
      }
        break;
      case SSE: { // sizebits j start limit
        cr.cxt=(h[i]+c8)*32;
        int pq=p[cp[2]]+992;
        if (pq<0) pq=0;
        if (pq>1983) pq=1983;
        int wt=pq&63;
        pq>>=6;
        assert(pq>=0 && pq<=30);
        cr.cxt+=pq;
        p[i]=stretch(((cr.cm(cr.cxt)>>10)*(64-wt)+(cr.cm(cr.cxt+1)>>10)*wt)>>13);
        cr.cxt+=wt>>5;
      }
        break;
      default:
        error("component predict not implemented");
    }
    cp+=compsize[cp[0]];
    assert(cp<&z.header[z.cend]);
    assert(p[i]>=-2048 && p[i]<2048);
  }
  assert(cp[0]==NONE);
  return squash(p[n-1]);
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0x70, %rsp
movq %rdi, -0x8(%rbp)
movq -0x8(%rbp), %rax
movq %rax, -0x58(%rbp)
movq 0x808(%rax), %rdi
addq $0x10, %rdi
movl $0x6, %esi
callq 0x30630
movq %rax, %rcx
movq -0x58(%rbp), %rax
movzbl (%rcx), %ecx
movl %ecx, -0xc(%rbp)
movq 0x808(%rax), %rdi
addq $0x10, %rdi
movl $0x7, %esi
callq 0x30630
movq %rax, -0x18(%rbp)
movl $0x0, -0x1c(%rbp)
movl -0x1c(%rbp), %eax
cmpl -0xc(%rbp), %eax
jge 0x12926
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
imulq $0x70, %rcx, %rcx
leaq 0x810(%rax,%rcx), %rax
movq %rax, -0x28(%rbp)
movq -0x18(%rbp), %rax
movzbl (%rax), %eax
decl %eax
movl %eax, %ecx
movq %rcx, -0x60(%rbp)
subl $0x8, %eax
ja 0x128eb
movq -0x60(%rbp), %rax
leaq 0x22437(%rip), %rcx     # 0x347c4
movslq (%rcx,%rax,4), %rax
addq %rcx, %rax
jmpq *%rax
jmp 0x128f7
movq -0x58(%rbp), %rcx
movslq -0x1c(%rbp), %rax
movl 0x408(%rcx,%rax,4), %eax
xorl 0x4(%rcx), %eax
movl %eax, %eax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x30970
movq -0x58(%rbp), %rdi
movl (%rax), %esi
shrl $0x11, %esi
callq 0x30cf0
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rax
cmpl $0x1, (%rax)
je 0x12408
movq -0x58(%rbp), %rax
movl (%rax), %eax
andl $0xf0, %eax
cmpl $0x10, %eax
jne 0x12441
movq -0x58(%rbp), %rdi
movq -0x28(%rbp), %rsi
addq $0x40, %rsi
movq -0x18(%rbp), %rax
movzbl 0x1(%rax), %edx
addl $0x2, %edx
movslq -0x1c(%rbp), %rax
movl 0x408(%rdi,%rax,4), %ecx
movl (%rdi), %eax
shll $0x4, %eax
addl %eax, %ecx
callq 0x12950
movq %rax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x58(%rbp), %rax
movq -0x28(%rbp), %rdi
addq $0x40, %rdi
movq -0x28(%rbp), %rcx
movq 0x20(%rcx), %rsi
movl 0x4(%rax), %eax
andl $0xf, %eax
cltq
addq %rax, %rsi
callq 0x30630
movzbl (%rax), %eax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x30970
movq -0x58(%rbp), %rdi
movl (%rax), %esi
shrl $0x8, %esi
callq 0x30cf0
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x28(%rbp), %rax
cmpq $0x0, 0x10(%rax)
jne 0x124c5
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl $0x0, 0x8(%rax,%rcx,4)
jmp 0x12541
movq -0x28(%rbp), %rdi
addq $0x40, %rdi
movq -0x28(%rbp), %rax
movq (%rax), %rsi
movq -0x28(%rbp), %rax
subq 0x18(%rax), %rsi
callq 0x30940
movq -0x58(%rbp), %rdi
movzbl (%rax), %eax
movq -0x28(%rbp), %rdx
movl $0x7, %ecx
subq 0x8(%rdx), %rcx
sarl %cl, %eax
andl $0x1, %eax
movslq %eax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x28(%rbp), %rax
movq 0x10(%rax), %rax
movslq 0x7814(%rdi,%rax,4), %rax
movq -0x28(%rbp), %rcx
imulq $-0x2, 0x20(%rcx), %rcx
addq $0x1, %rcx
imulq %rcx, %rax
andq $0x7fff, %rax           # imm = 0x7FFF
movl %eax, %esi
callq 0x30cf0
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rax
movq -0x18(%rbp), %rcx
movzbl 0x1(%rcx), %ecx
movl 0x8(%rax,%rcx,4), %edx
movq -0x18(%rbp), %rcx
movzbl 0x3(%rcx), %ecx
imull %ecx, %edx
movq -0x18(%rbp), %rcx
movzbl 0x2(%rcx), %ecx
movl 0x8(%rax,%rcx,4), %ecx
movq -0x18(%rbp), %rsi
movzbl 0x3(%rsi), %edi
movl $0x100, %esi            # imm = 0x100
subl %edi, %esi
imull %esi, %ecx
addl %ecx, %edx
sarl $0x8, %edx
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rcx
movslq -0x1c(%rbp), %rax
movl 0x408(%rcx,%rax,4), %eax
movl (%rcx), %ecx
movq -0x18(%rbp), %rdx
movzbl 0x5(%rdx), %edx
andl %edx, %ecx
addl %ecx, %eax
movl %eax, %eax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movq 0x20(%rax), %rax
subq $0x1, %rax
andq %rax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x58, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x30c90
movq %rax, %rcx
movq -0x58(%rbp), %rax
movzwl (%rcx), %ecx
movl %ecx, -0x2c(%rbp)
movl -0x2c(%rbp), %edx
movq -0x18(%rbp), %rcx
movzbl 0x2(%rcx), %ecx
imull 0x8(%rax,%rcx,4), %edx
movl $0x10000, %ecx          # imm = 0x10000
subl -0x2c(%rbp), %ecx
movq -0x18(%rbp), %rsi
movzbl 0x3(%rsi), %esi
imull 0x8(%rax,%rsi,4), %ecx
addl %ecx, %edx
sarl $0x10, %edx
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rcx
movq -0x18(%rbp), %rax
movzbl 0x3(%rax), %eax
movl %eax, -0x30(%rbp)
movslq -0x1c(%rbp), %rax
movl 0x408(%rcx,%rax,4), %eax
movl (%rcx), %ecx
movq -0x18(%rbp), %rdx
movzbl 0x5(%rdx), %edx
andl %edx, %ecx
addl %ecx, %eax
movl %eax, %eax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rcx
movq -0x28(%rbp), %rax
movq 0x20(%rax), %rax
subq $0x1, %rax
andq %rax, %rcx
movslq -0x30(%rbp), %rax
imulq %rax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x30880
movq %rax, %rcx
movq -0x58(%rbp), %rax
movq %rcx, -0x38(%rbp)
movslq -0x1c(%rbp), %rcx
movl $0x0, 0x8(%rax,%rcx,4)
movl $0x0, -0x3c(%rbp)
movl -0x3c(%rbp), %eax
cmpl -0x30(%rbp), %eax
jge 0x126f4
movq -0x58(%rbp), %rax
movq -0x38(%rbp), %rcx
movslq -0x3c(%rbp), %rdx
movl (%rcx,%rdx,4), %edx
sarl $0x8, %edx
movq -0x18(%rbp), %rcx
movzbl 0x2(%rcx), %ecx
addl -0x3c(%rbp), %ecx
movslq %ecx, %rcx
imull 0x8(%rax,%rcx,4), %edx
movslq -0x1c(%rbp), %rcx
addl 0x8(%rax,%rcx,4), %edx
movl %edx, 0x8(%rax,%rcx,4)
movl -0x3c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x3c(%rbp)
jmp 0x126b0
movq -0x58(%rbp), %rdi
movslq -0x1c(%rbp), %rax
movl 0x8(%rdi,%rax,4), %esi
sarl $0x8, %esi
callq 0x30d40
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rax
cmpl $0x1, (%rax)
je 0x12734
movq -0x58(%rbp), %rax
movl (%rax), %eax
andl $0xf0, %eax
cmpl $0x10, %eax
jne 0x1276d
movq -0x58(%rbp), %rdi
movq -0x28(%rbp), %rsi
addq $0x40, %rsi
movq -0x18(%rbp), %rax
movzbl 0x1(%rax), %edx
addl $0x2, %edx
movslq -0x1c(%rbp), %rax
movl 0x408(%rdi,%rax,4), %ecx
movl (%rdi), %eax
shll $0x4, %eax
addl %eax, %ecx
callq 0x12950
movq %rax, %rcx
movq -0x28(%rbp), %rax
movq %rcx, 0x20(%rax)
movq -0x58(%rbp), %rax
movq -0x28(%rbp), %rdi
addq $0x40, %rdi
movq -0x28(%rbp), %rcx
movq 0x20(%rcx), %rsi
movl 0x4(%rax), %eax
andl $0xf, %eax
cltq
addq %rax, %rsi
callq 0x30630
movzbl (%rax), %eax
movl %eax, %ecx
movq -0x28(%rbp), %rax
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
shlq %rsi
callq 0x30880
movq -0x58(%rbp), %rdi
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
movl (%rax), %esi
movq -0x18(%rbp), %rax
movzbl 0x2(%rax), %eax
imull 0x8(%rdi,%rax,4), %esi
movq -0x48(%rbp), %rax
movl 0x4(%rax), %eax
shll $0x6, %eax
addl %eax, %esi
sarl $0x10, %esi
callq 0x30d40
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
jmp 0x128f7
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl 0x408(%rax,%rcx,4), %ecx
addl (%rax), %ecx
shll $0x5, %ecx
movl %ecx, %ecx
movl %ecx, %edx
movq -0x28(%rbp), %rcx
movq %rdx, 0x8(%rcx)
movq -0x18(%rbp), %rcx
movzbl 0x2(%rcx), %ecx
movl 0x8(%rax,%rcx,4), %eax
addl $0x3e0, %eax            # imm = 0x3E0
movl %eax, -0x4c(%rbp)
cmpl $0x0, -0x4c(%rbp)
jge 0x12839
movl $0x0, -0x4c(%rbp)
cmpl $0x7bf, -0x4c(%rbp)     # imm = 0x7BF
jle 0x12849
movl $0x7bf, -0x4c(%rbp)     # imm = 0x7BF
movl -0x4c(%rbp), %eax
andl $0x3f, %eax
movl %eax, -0x50(%rbp)
movl -0x4c(%rbp), %eax
sarl $0x6, %eax
movl %eax, -0x4c(%rbp)
movslq -0x4c(%rbp), %rcx
movq -0x28(%rbp), %rax
addq 0x8(%rax), %rcx
movq %rcx, 0x8(%rax)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
callq 0x30970
movl (%rax), %eax
shrl $0xa, %eax
movl $0x40, %ecx
subl -0x50(%rbp), %ecx
imull %ecx, %eax
movl %eax, -0x64(%rbp)
movq -0x28(%rbp), %rdi
addq $0x28, %rdi
movq -0x28(%rbp), %rax
movq 0x8(%rax), %rsi
addq $0x1, %rsi
callq 0x30970
movl -0x64(%rbp), %esi
movq -0x58(%rbp), %rdi
movl (%rax), %eax
shrl $0xa, %eax
imull -0x50(%rbp), %eax
addl %eax, %esi
shrl $0xd, %esi
callq 0x30cf0
movl %eax, %edx
movq -0x58(%rbp), %rax
movslq -0x1c(%rbp), %rcx
movl %edx, 0x8(%rax,%rcx,4)
movl -0x50(%rbp), %eax
sarl $0x5, %eax
movslq %eax, %rcx
movq -0x28(%rbp), %rax
addq 0x8(%rax), %rcx
movq %rcx, 0x8(%rax)
jmp 0x128f7
leaq 0x257cc(%rip), %rdi     # 0x380be
callq 0x5720
movq -0x18(%rbp), %rax
movzbl (%rax), %eax
movl %eax, %ecx
leaq 0x222b9(%rip), %rax     # 0x34bc0
movl (%rax,%rcx,4), %ecx
movq -0x18(%rbp), %rax
movslq %ecx, %rcx
addq %rcx, %rax
movq %rax, -0x18(%rbp)
movl -0x1c(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x1c(%rbp)
jmp 0x12346
movq -0x58(%rbp), %rdi
movl -0xc(%rbp), %eax
subl $0x1, %eax
cltq
movl 0x8(%rdi,%rax,4), %esi
callq 0x30d10
addq $0x70, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)