// File: marxn[P]pupp/3rdparty/gmp/mpn/mul_fft.c
// Function: mpn_fft_mul_modF_K
static void
mpn_fft_mul_modF_K (mp_ptr *ap, mp_ptr *bp, mp_size_t n, mp_size_t K)
{
  int i;
  int sqr = (ap == bp);
  TMP_DECL;

  TMP_MARK;

  if (n >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
    {
      mp_size_t K2, nprime2, Nprime2, M2, maxLK, l, Mp2;
      int k;
      int **fft_l, *tmp;
      mp_ptr *Ap, *Bp, A, B, T;

      k = mpn_fft_best_k (n, sqr);
      K2 = (mp_size_t) 1 << k;
      ASSERT_ALWAYS((n & (K2 - 1)) == 0);
      maxLK = (K2 > GMP_NUMB_BITS) ? K2 : GMP_NUMB_BITS;
      M2 = n * GMP_NUMB_BITS >> k;
      l = n >> k;
      Nprime2 = ((2 * M2 + k + 2 + maxLK) / maxLK) * maxLK;
      /* Nprime2 = ceil((2*M2+k+3)/maxLK)*maxLK*/
      nprime2 = Nprime2 / GMP_NUMB_BITS;

      /* we should ensure that nprime2 is a multiple of the next K */
      if (nprime2 >= (sqr ? SQR_FFT_MODF_THRESHOLD : MUL_FFT_MODF_THRESHOLD))
	{
	  mp_size_t K3;
	  for (;;)
	    {
	      K3 = (mp_size_t) 1 << mpn_fft_best_k (nprime2, sqr);
	      if ((nprime2 & (K3 - 1)) == 0)
		break;
	      nprime2 = (nprime2 + K3 - 1) & -K3;
	      Nprime2 = nprime2 * GMP_LIMB_BITS;
	      /* warning: since nprime2 changed, K3 may change too! */
	    }
	}
      ASSERT_ALWAYS(nprime2 < n); /* otherwise we'll loop */

      Mp2 = Nprime2 >> k;

      Ap = TMP_BALLOC_MP_PTRS (K2);
      Bp = TMP_BALLOC_MP_PTRS (K2);
      A = TMP_BALLOC_LIMBS (2 * (nprime2 + 1) << k);
      T = TMP_BALLOC_LIMBS (2 * (nprime2 + 1));
      B = A + ((nprime2 + 1) << k);
      fft_l = TMP_BALLOC_TYPE (k + 1, int *);
      tmp = TMP_BALLOC_TYPE ((size_t) 2 << k, int);
      for (i = 0; i <= k; i++)
	{
	  fft_l[i] = tmp;
	  tmp += (mp_size_t) 1 << i;
	}

      mpn_fft_initl (fft_l, k);

      TRACE (printf ("recurse: %ldx%ld limbs -> %ld times %ldx%ld (%1.2f)\n", n,
		    n, K2, nprime2, nprime2, 2.0*(double)n/nprime2/K2));
      for (i = 0; i < K; i++, ap++, bp++)
	{
	  mp_limb_t cy;
	  mpn_fft_normalize (*ap, n);
	  if (!sqr)
	    mpn_fft_normalize (*bp, n);

	  mpn_mul_fft_decompose (A, Ap, K2, nprime2, *ap, (l << k) + 1, l, Mp2, T);
	  if (!sqr)
	    mpn_mul_fft_decompose (B, Bp, K2, nprime2, *bp, (l << k) + 1, l, Mp2, T);

	  cy = mpn_mul_fft_internal (*ap, n, k, Ap, Bp, A, B, nprime2,
				     l, Mp2, fft_l, T, sqr);
	  (*ap)[n] = cy;
	}
    }
  else
    {
      mp_ptr a, b, tp, tpn;
      mp_limb_t cc;
      mp_size_t n2 = 2 * n;
      tp = TMP_BALLOC_LIMBS (n2);
      tpn = tp + n;
      TRACE (printf ("  mpn_mul_n %ld of %ld limbs\n", K, n));
      for (i = 0; i < K; i++)
	{
	  a = *ap++;
	  b = *bp++;
	  if (sqr)
	    mpn_sqr (tp, a, n);
	  else
	    mpn_mul_n (tp, b, a, n);
	  if (a[n] != 0)
	    cc = mpn_add_n (tpn, tpn, b, n);
	  else
	    cc = 0;
	  if (b[n] != 0)
	    cc += mpn_add_n (tpn, tpn, a, n) + a[n];
	  if (cc != 0)
	    {
	      /* FIXME: use MPN_INCR_U here, since carry is not expected.  */
	      cc = mpn_add_1 (tp, tp, n2, cc);
	      ASSERT (cc == 0);
	    }
	  a[n] = mpn_sub_n (a, tp, tpn, n) && mpn_add_1 (a, a, n, CNST_LIMB(1));
	}
    }
  TMP_FREE;
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
pushq %r15
pushq %r14
pushq %r12
pushq %rbx
subq $0x140, %rsp            # imm = 0x140
movq %rdi, -0x28(%rbp)
movq %rsi, -0x30(%rbp)
movq %rdx, -0x38(%rbp)
movq %rcx, -0x40(%rbp)
movq -0x28(%rbp), %rax
cmpq -0x30(%rbp), %rax
sete %al
andb $0x1, %al
movzbl %al, %eax
movl %eax, -0x48(%rbp)
movq $0x0, -0x50(%rbp)
movq -0x38(%rbp), %rax
movl -0x48(%rbp), %esi
movl $0x28e, %ecx            # imm = 0x28E
movl $0x23a, %edx            # imm = 0x23A
cmpl $0x0, %esi
cmovnel %edx, %ecx
movslq %ecx, %rcx
cmpq %rcx, %rax
jl 0x58867
movq -0x38(%rbp), %rdi
movl -0x48(%rbp), %esi
callq 0x56ab0
movl %eax, -0x8c(%rbp)
movl -0x8c(%rbp), %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, -0x58(%rbp)
movq -0x38(%rbp), %rax
movq -0x58(%rbp), %rcx
subq $0x1, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
sete %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x583ee
leaq 0xbc73(%rip), %rdi      # 0x64050
movl $0x1c1, %esi            # imm = 0x1C1
leaq 0xbca8(%rip), %rdx      # 0x64091
callq 0x562c0
jmp 0x583f0
cmpq $0x40, -0x58(%rbp)
jle 0x58404
movq -0x58(%rbp), %rax
movq %rax, -0x110(%rbp)
jmp 0x58412
movl $0x40, %eax
movq %rax, -0x110(%rbp)
jmp 0x58412
movq -0x110(%rbp), %rax
movq %rax, -0x78(%rbp)
movq -0x38(%rbp), %rax
shlq $0x6, %rax
movl -0x8c(%rbp), %ecx
sarq %cl, %rax
movq %rax, -0x70(%rbp)
movq -0x38(%rbp), %rax
movl -0x8c(%rbp), %ecx
sarq %cl, %rax
movq %rax, -0x80(%rbp)
movq -0x70(%rbp), %rax
shlq %rax
movslq -0x8c(%rbp), %rcx
addq %rcx, %rax
addq $0x2, %rax
addq -0x78(%rbp), %rax
cqto
idivq -0x78(%rbp)
imulq -0x78(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x68(%rbp), %rax
movl $0x40, %ecx
cqto
idivq %rcx
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
movl -0x48(%rbp), %esi
movl $0x28e, %ecx            # imm = 0x28E
movl $0x23a, %edx            # imm = 0x23A
cmpl $0x0, %esi
cmovnel %edx, %ecx
movslq %ecx, %rcx
cmpq %rcx, %rax
jl 0x58506
jmp 0x5849e
movq -0x60(%rbp), %rdi
movl -0x48(%rbp), %esi
callq 0x56ab0
movl %eax, %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
movq %rax, -0xd0(%rbp)
movq -0x60(%rbp), %rax
movq -0xd0(%rbp), %rcx
subq $0x1, %rcx
andq %rcx, %rax
cmpq $0x0, %rax
jne 0x584d7
jmp 0x58504
movq -0x60(%rbp), %rax
addq -0xd0(%rbp), %rax
subq $0x1, %rax
xorl %ecx, %ecx
subq -0xd0(%rbp), %rcx
andq %rcx, %rax
movq %rax, -0x60(%rbp)
movq -0x60(%rbp), %rax
shlq $0x6, %rax
movq %rax, -0x68(%rbp)
jmp 0x5849e
jmp 0x58506
jmp 0x58508
movq -0x60(%rbp), %rax
cmpq -0x38(%rbp), %rax
setl %al
xorb $-0x1, %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x58545
leaq 0xbb1c(%rip), %rdi      # 0x64050
movl $0x1d7, %esi            # imm = 0x1D7
leaq 0xbb65(%rip), %rdx      # 0x640a5
callq 0x562c0
jmp 0x58547
movq -0x68(%rbp), %rax
movl -0x8c(%rbp), %ecx
sarq %cl, %rax
movq %rax, -0x88(%rbp)
movq -0x58(%rbp), %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xa8(%rbp)
movq -0x58(%rbp), %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xb0(%rbp)
movq -0x60(%rbp), %rsi
addq $0x1, %rsi
shlq %rsi
movl -0x8c(%rbp), %eax
movl %eax, %ecx
shlq %cl, %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xb8(%rbp)
movq -0x60(%rbp), %rsi
addq $0x1, %rsi
shlq %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xc8(%rbp)
movq -0xb8(%rbp), %rax
movq -0x60(%rbp), %rdx
addq $0x1, %rdx
movl -0x8c(%rbp), %ecx
shlq %cl, %rdx
movq %rdx, %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0xc0(%rbp)
movl -0x8c(%rbp), %eax
addl $0x1, %eax
movslq %eax, %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0x98(%rbp)
movl -0x8c(%rbp), %eax
movl %eax, %ecx
movl $0x2, %esi
shlq %cl, %rsi
shlq $0x2, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xa0(%rbp)
movl $0x0, -0x44(%rbp)
movl -0x44(%rbp), %eax
cmpl -0x8c(%rbp), %eax
jg 0x58693
movq -0xa0(%rbp), %rdx
movq -0x98(%rbp), %rax
movslq -0x44(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x44(%rbp), %eax
movl %eax, %ecx
movl $0x1, %eax
shlq %cl, %rax
shlq $0x2, %rax
addq -0xa0(%rbp), %rax
movq %rax, -0xa0(%rbp)
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x58648
movq -0x98(%rbp), %rdi
movl -0x8c(%rbp), %esi
callq 0x570a0
movl $0x0, -0x44(%rbp)
movslq -0x44(%rbp), %rax
cmpq -0x40(%rbp), %rax
jge 0x58862
movq -0x28(%rbp), %rax
movq (%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x59020
cmpl $0x0, -0x48(%rbp)
jne 0x586e0
movq -0x30(%rbp), %rax
movq (%rax), %rdi
movq -0x38(%rbp), %rsi
callq 0x59020
movq -0xb8(%rbp), %rdi
movq -0xa8(%rbp), %rsi
movq -0x58(%rbp), %rdx
movq -0x60(%rbp), %rax
movq %rax, -0x118(%rbp)
movq -0x28(%rbp), %rax
movq (%rax), %r8
movq -0x80(%rbp), %r9
movl -0x8c(%rbp), %eax
movl %eax, %ecx
shlq %cl, %r9
movq -0x118(%rbp), %rcx
addq $0x1, %r9
movq -0x80(%rbp), %r11
movq -0x88(%rbp), %r10
movq -0xc8(%rbp), %rax
movq %r11, (%rsp)
movq %r10, 0x8(%rsp)
movq %rax, 0x10(%rsp)
callq 0x571c0
cmpl $0x0, -0x48(%rbp)
jne 0x587ac
movq -0xc0(%rbp), %rdi
movq -0xb0(%rbp), %rsi
movq -0x58(%rbp), %rdx
movq -0x60(%rbp), %rax
movq %rax, -0x120(%rbp)
movq -0x30(%rbp), %rax
movq (%rax), %r8
movq -0x80(%rbp), %r9
movl -0x8c(%rbp), %eax
movl %eax, %ecx
shlq %cl, %r9
movq -0x120(%rbp), %rcx
addq $0x1, %r9
movq -0x80(%rbp), %r11
movq -0x88(%rbp), %r10
movq -0xc8(%rbp), %rax
movq %r11, (%rsp)
movq %r10, 0x8(%rsp)
movq %rax, 0x10(%rsp)
callq 0x571c0
movq -0x28(%rbp), %rax
movq (%rax), %rdi
movq -0x38(%rbp), %rsi
movl -0x8c(%rbp), %edx
movq -0xa8(%rbp), %rcx
movq -0xb0(%rbp), %r8
movq -0xb8(%rbp), %r9
movq -0xc0(%rbp), %r12
movq -0x60(%rbp), %r15
movq -0x80(%rbp), %r14
movq -0x88(%rbp), %rbx
movq -0x98(%rbp), %r11
movq -0xc8(%rbp), %r10
movl -0x48(%rbp), %eax
movq %r12, (%rsp)
movq %r15, 0x8(%rsp)
movq %r14, 0x10(%rsp)
movq %rbx, 0x18(%rsp)
movq %r11, 0x20(%rsp)
movq %r10, 0x28(%rsp)
movl %eax, 0x30(%rsp)
callq 0x57650
movq %rax, -0xd8(%rbp)
movq -0xd8(%rbp), %rdx
movq -0x28(%rbp), %rax
movq (%rax), %rax
movq -0x38(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
movq -0x28(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x28(%rbp)
movq -0x30(%rbp), %rax
addq $0x8, %rax
movq %rax, -0x30(%rbp)
jmp 0x586ac
jmp 0x58a79
movq -0x38(%rbp), %rax
shlq %rax
movq %rax, -0x108(%rbp)
movq -0x108(%rbp), %rsi
shlq $0x3, %rsi
leaq -0x50(%rbp), %rdi
callq 0x56430
movq %rax, -0xf0(%rbp)
movq -0xf0(%rbp), %rax
movq -0x38(%rbp), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0xf8(%rbp)
movl $0x0, -0x44(%rbp)
movslq -0x44(%rbp), %rax
cmpq -0x40(%rbp), %rax
jge 0x58a77
movq -0x28(%rbp), %rax
movq %rax, %rcx
addq $0x8, %rcx
movq %rcx, -0x28(%rbp)
movq (%rax), %rax
movq %rax, -0xe0(%rbp)
movq -0x30(%rbp), %rax
movq %rax, %rcx
addq $0x8, %rcx
movq %rcx, -0x30(%rbp)
movq (%rax), %rax
movq %rax, -0xe8(%rbp)
cmpl $0x0, -0x48(%rbp)
je 0x5890f
movq -0xf0(%rbp), %rdi
movq -0xe0(%rbp), %rsi
movq -0x38(%rbp), %rdx
callq 0x392b0
jmp 0x5892d
movq -0xf0(%rbp), %rdi
movq -0xe8(%rbp), %rsi
movq -0xe0(%rbp), %rdx
movq -0x38(%rbp), %rcx
callq 0x39000
movq -0xe0(%rbp), %rax
movq -0x38(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x58966
movq -0xf8(%rbp), %rdi
movq -0xf8(%rbp), %rsi
movq -0xe8(%rbp), %rdx
movq -0x38(%rbp), %rcx
callq 0x36c80
movq %rax, -0x100(%rbp)
jmp 0x58971
movq $0x0, -0x100(%rbp)
movq -0xe8(%rbp), %rax
movq -0x38(%rbp), %rcx
cmpq $0x0, (%rax,%rcx,8)
je 0x589be
movq -0xf8(%rbp), %rdi
movq -0xf8(%rbp), %rsi
movq -0xe0(%rbp), %rdx
movq -0x38(%rbp), %rcx
callq 0x36c80
movq -0xe0(%rbp), %rcx
movq -0x38(%rbp), %rdx
addq (%rcx,%rdx,8), %rax
addq -0x100(%rbp), %rax
movq %rax, -0x100(%rbp)
cmpq $0x0, -0x100(%rbp)
je 0x589f4
movq -0xf0(%rbp), %rdi
movq -0xf0(%rbp), %rsi
movq -0x108(%rbp), %rdx
movq -0x100(%rbp), %rcx
callq 0x564f0
movq %rax, -0x100(%rbp)
jmp 0x589f2
jmp 0x589f4
movq -0xe0(%rbp), %rdi
movq -0xf0(%rbp), %rsi
movq -0xf8(%rbp), %rdx
movq -0x38(%rbp), %rcx
callq 0x36fe0
movq %rax, %rcx
xorl %eax, %eax
cmpq $0x0, %rcx
movb %al, -0x121(%rbp)
je 0x58a4c
movq -0xe0(%rbp), %rdi
movq -0xe0(%rbp), %rsi
movq -0x38(%rbp), %rdx
movl $0x1, %ecx
callq 0x564f0
cmpq $0x0, %rax
setne %al
movb %al, -0x121(%rbp)
movb -0x121(%rbp), %al
andb $0x1, %al
movzbl %al, %eax
movslq %eax, %rdx
movq -0xe0(%rbp), %rax
movq -0x38(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
movl -0x44(%rbp), %eax
addl $0x1, %eax
movl %eax, -0x44(%rbp)
jmp 0x588b0
jmp 0x58a79
jmp 0x58a7b
cmpq $0x0, -0x50(%rbp)
setne %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x58aa4
movq -0x50(%rbp), %rdi
callq 0x564a0
jmp 0x58aa6
addq $0x140, %rsp            # imm = 0x140
popq %rbx
popq %r12
popq %r14
popq %r15
popq %rbp
retq
nopw %cs:(%rax,%rax)