// File: lemire[P]backward_multiplication/include/backwardmultiply.h
// Function: backwardmultiply::multiplication_backward_limit_resume(unsigned long, unsigned long const*, unsigned long, unsigned long*, unsigned long, unsigned long&)
size_t multiplication_backward_limit_resume(uint64_t w, const uint64_t *b,
                                            size_t n, uint64_t *output,
                                            size_t minexactwords,
                                            size_t &previousindex) {
  if (n == 0) { // special case
    std::fill(output, output + n + 1, 0);
    return n + 1; // we are done!!!
  }
  if (previousindex > n) {
    // assume we are done
    return n + 1;
  }
  if (previousindex == n) {
    previousindex = n - 1;
    auto p = full_multiplication(w, b[n - 1]);
    output[n - 1] = p.low;
    output[n] = p.high;
    if (minexactwords <= 1) {
      // check if addition overflows
      if (p.low + w - 1 >= p.low) {
        // we are good
        return 1;
      }
    }
  }

  for (size_t i = previousindex - 1; i != SIZE_MAX; i--) {
    auto p = full_multiplication(w, b[i]);
    output[i] = p.low;
    bool overflow = (output[i + 1] + p.high < output[i + 1]);
    output[i + 1] += p.high;
    for (size_t j = i + 2; overflow; j++) {
      output[j]++;
      overflow = (output[j] == 0);
    }
    if (minexactwords <= n - i) {
      // check if addition overflows
      if (p.low + w - 1 >= p.low) {
        // we are good
        previousindex = i;
        return n - i;
      }
      if (minexactwords < n - i) {
        // then the only way we could overflow is if the following is true
        if (output[i + 1] != 0xFFFFFFFFFFFFFFFF) {
          previousindex = i;
          return n - i - 1;
        }
      }
    }
  }
  previousindex = SIZE_MAX;
  return n + 1;
}

// Assembly:
subq $0x78, %rsp
movq %rdi, 0x68(%rsp)
movq %rsi, 0x60(%rsp)
movq %rdx, 0x58(%rsp)
movq %rcx, 0x50(%rsp)
movq %r8, 0x48(%rsp)
movq %r9, 0x40(%rsp)
cmpq $0x0, 0x58(%rsp)
jne 0x18a9
movq 0x50(%rsp), %rdi
movq 0x50(%rsp), %rsi
movq 0x58(%rsp), %rax
shlq $0x3, %rax
addq %rax, %rsi
addq $0x8, %rsi
movl $0x0, 0x3c(%rsp)
leaq 0x3c(%rsp), %rdx
callq 0x21e0
movq 0x58(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x70(%rsp)
jmp 0x1b15
movq 0x40(%rsp), %rax
movq (%rax), %rax
cmpq 0x58(%rsp), %rax
jbe 0x18cb
movq 0x58(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x70(%rsp)
jmp 0x1b15
movq 0x40(%rsp), %rax
movq (%rax), %rax
cmpq 0x58(%rsp), %rax
jne 0x196e
movq 0x58(%rsp), %rcx
subq $0x1, %rcx
movq 0x40(%rsp), %rax
movq %rcx, (%rax)
movq 0x68(%rsp), %rdi
movq 0x60(%rsp), %rax
movq 0x58(%rsp), %rcx
subq $0x1, %rcx
movq (%rax,%rcx,8), %rsi
callq 0x1280
movq %rax, 0x28(%rsp)
movq %rdx, 0x30(%rsp)
movq 0x28(%rsp), %rdx
movq 0x50(%rsp), %rax
movq 0x58(%rsp), %rcx
subq $0x1, %rcx
movq %rdx, (%rax,%rcx,8)
movq 0x30(%rsp), %rdx
movq 0x50(%rsp), %rax
movq 0x58(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
cmpq $0x1, 0x48(%rsp)
ja 0x196c
movq 0x28(%rsp), %rax
addq 0x68(%rsp), %rax
subq $0x1, %rax
cmpq 0x28(%rsp), %rax
jb 0x196a
movq $0x1, 0x70(%rsp)
jmp 0x1b15
jmp 0x196c
jmp 0x196e
movq 0x40(%rsp), %rax
movq (%rax), %rax
subq $0x1, %rax
movq %rax, 0x20(%rsp)
cmpq $-0x1, 0x20(%rsp)
je 0x1afb
movq 0x68(%rsp), %rdi
movq 0x60(%rsp), %rax
movq 0x20(%rsp), %rcx
movq (%rax,%rcx,8), %rsi
callq 0x1280
movq %rax, 0x10(%rsp)
movq %rdx, 0x18(%rsp)
movq 0x10(%rsp), %rdx
movq 0x50(%rsp), %rax
movq 0x20(%rsp), %rcx
movq %rdx, (%rax,%rcx,8)
movq 0x50(%rsp), %rax
movq 0x20(%rsp), %rcx
movq 0x8(%rax,%rcx,8), %rax
addq 0x18(%rsp), %rax
movq 0x50(%rsp), %rcx
movq 0x20(%rsp), %rdx
cmpq 0x8(%rcx,%rdx,8), %rax
setb %al
andb $0x1, %al
movb %al, 0xf(%rsp)
movq 0x18(%rsp), %rdx
movq 0x50(%rsp), %rax
movq 0x20(%rsp), %rcx
addq 0x8(%rax,%rcx,8), %rdx
movq %rdx, 0x8(%rax,%rcx,8)
movq 0x20(%rsp), %rax
addq $0x2, %rax
movq %rax, (%rsp)
testb $0x1, 0xf(%rsp)
je 0x1a53
movq 0x50(%rsp), %rax
movq (%rsp), %rcx
movq (%rax,%rcx,8), %rdx
addq $0x1, %rdx
movq %rdx, (%rax,%rcx,8)
movq 0x50(%rsp), %rax
movq (%rsp), %rcx
cmpq $0x0, (%rax,%rcx,8)
sete %al
andb $0x1, %al
movb %al, 0xf(%rsp)
movq (%rsp), %rax
addq $0x1, %rax
movq %rax, (%rsp)
jmp 0x1a12
movq 0x48(%rsp), %rax
movq 0x58(%rsp), %rcx
subq 0x20(%rsp), %rcx
cmpq %rcx, %rax
ja 0x1ae6
movq 0x10(%rsp), %rax
addq 0x68(%rsp), %rax
subq $0x1, %rax
cmpq 0x10(%rsp), %rax
jb 0x1a9a
movq 0x20(%rsp), %rcx
movq 0x40(%rsp), %rax
movq %rcx, (%rax)
movq 0x58(%rsp), %rax
subq 0x20(%rsp), %rax
movq %rax, 0x70(%rsp)
jmp 0x1b15
movq 0x48(%rsp), %rax
movq 0x58(%rsp), %rcx
subq 0x20(%rsp), %rcx
cmpq %rcx, %rax
jae 0x1ae4
movq 0x50(%rsp), %rax
movq 0x20(%rsp), %rcx
cmpq $-0x1, 0x8(%rax,%rcx,8)
je 0x1ae2
movq 0x20(%rsp), %rcx
movq 0x40(%rsp), %rax
movq %rcx, (%rax)
movq 0x58(%rsp), %rax
subq 0x20(%rsp), %rax
subq $0x1, %rax
movq %rax, 0x70(%rsp)
jmp 0x1b15
jmp 0x1ae4
jmp 0x1ae6
jmp 0x1ae8
movq 0x20(%rsp), %rax
addq $-0x1, %rax
movq %rax, 0x20(%rsp)
jmp 0x197f
movq 0x40(%rsp), %rax
movq $-0x1, (%rax)
movq 0x58(%rsp), %rax
addq $0x1, %rax
movq %rax, 0x70(%rsp)
movq 0x70(%rsp), %rax
addq $0x78, %rsp
retq
nop