// File: marxn[P]pupp/3rdparty/gmp/mpn/sqrmod_bnm1.c
// Function: _gmpn_sqrmod_bnm1
void
mpn_sqrmod_bnm1 (mp_ptr rp, mp_size_t rn, mp_srcptr ap, mp_size_t an, mp_ptr tp)
{
  ASSERT (0 < an);
  ASSERT (an <= rn);

  if ((rn & 1) != 0 || BELOW_THRESHOLD (rn, SQRMOD_BNM1_THRESHOLD))
    {
      if (UNLIKELY (an < rn))
	{
	  if (UNLIKELY (2*an <= rn))
	    {
	      mpn_sqr (rp, ap, an);
	    }
	  else
	    {
	      mp_limb_t cy;
	      mpn_sqr (tp, ap, an);
	      cy = mpn_add (rp, tp, rn, tp + rn, 2*an - rn);
	      MPN_INCR_U (rp, rn, cy);
	    }
	}
      else
	mpn_bc_sqrmod_bnm1 (rp, ap, rn, tp);
    }
  else
    {
      mp_size_t n;
      mp_limb_t cy;
      mp_limb_t hi;

      n = rn >> 1;

      ASSERT (2*an > n);

      /* Compute xm = a^2 mod (B^n - 1), xp = a^2 mod (B^n + 1)
	 and crt together as

	 x = -xp * B^n + (B^n + 1) * [ (xp + xm)/2 mod (B^n-1)]
      */

#define a0 ap
#define a1 (ap + n)

#define xp  tp	/* 2n + 2 */
      /* am1  maybe in {xp, n} */
#define sp1 (tp + 2*n + 2)
      /* ap1  maybe in {sp1, n + 1} */

      {
	mp_srcptr am1;
	mp_size_t anm;
	mp_ptr so;

	if (LIKELY (an > n))
	  {
	    so = xp + n;
	    am1 = xp;
	    cy = mpn_add (xp, a0, n, a1, an - n);
	    MPN_INCR_U (xp, n, cy);
	    anm = n;
	  }
	else
	  {
	    so = xp;
	    am1 = a0;
	    anm = an;
	  }

	mpn_sqrmod_bnm1 (rp, n, am1, anm, so);
      }

      {
	int       k;
	mp_srcptr ap1;
	mp_size_t anp;

	if (LIKELY (an > n)) {
	  ap1 = sp1;
	  cy = mpn_sub (sp1, a0, n, a1, an - n);
	  sp1[n] = 0;
	  MPN_INCR_U (sp1, n + 1, cy);
	  anp = n + ap1[n];
	} else {
	  ap1 = a0;
	  anp = an;
	}

	if (BELOW_THRESHOLD (n, MUL_FFT_MODF_THRESHOLD))
	  k=0;
	else
	  {
	    int mask;
	    k = mpn_fft_best_k (n, 1);
	    mask = (1<<k) -1;
	    while (n & mask) {k--; mask >>=1;};
	  }
	if (k >= FFT_FIRST_K)
	  xp[n] = mpn_mul_fft (xp, n, ap1, anp, ap1, anp, k);
	else if (UNLIKELY (ap1 == a0))
	  {
	    ASSERT (anp <= n);
	    ASSERT (2*anp > n);
	    mpn_sqr (xp, a0, an);
	    anp = 2*an - n;
	    cy = mpn_sub (xp, xp, n, xp + n, anp);
	    xp[n] = 0;
	    MPN_INCR_U (xp, n+1, cy);
	  }
	else
	  mpn_bc_sqrmod_bnp1 (xp, ap1, n, xp);
      }

      /* Here the CRT recomposition begins.

	 xm <- (xp + xm)/2 = (xp + xm)B^n/2 mod (B^n-1)
	 Division by 2 is a bitwise rotation.

	 Assumes xp normalised mod (B^n+1).

	 The residue class [0] is represented by [B^n-1]; except when
	 both input are ZERO.
      */

#if HAVE_NATIVE_mpn_rsh1add_n || HAVE_NATIVE_mpn_rsh1add_nc
#if HAVE_NATIVE_mpn_rsh1add_nc
      cy = mpn_rsh1add_nc(rp, rp, xp, n, xp[n]); /* B^n = 1 */
      hi = cy << (GMP_NUMB_BITS - 1);
      cy = 0;
      /* next update of rp[n-1] will set cy = 1 only if rp[n-1]+=hi
	 overflows, i.e. a further increment will not overflow again. */
#else /* ! _nc */
      cy = xp[n] + mpn_rsh1add_n(rp, rp, xp, n); /* B^n = 1 */
      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
      cy >>= 1;
      /* cy = 1 only if xp[n] = 1 i.e. {xp,n} = ZERO, this implies that
	 the rsh1add was a simple rshift: the top bit is 0. cy=1 => hi=0. */
#endif
#if GMP_NAIL_BITS == 0
      add_ssaaaa(cy, rp[n-1], cy, rp[n-1], CNST_LIMB(0), hi);
#else
      cy += (hi & rp[n-1]) >> (GMP_NUMB_BITS-1);
      rp[n-1] ^= hi;
#endif
#else /* ! HAVE_NATIVE_mpn_rsh1add_n */
#if HAVE_NATIVE_mpn_add_nc
      cy = mpn_add_nc(rp, rp, xp, n, xp[n]);
#else /* ! _nc */
      cy = xp[n] + mpn_add_n(rp, rp, xp, n); /* xp[n] == 1 implies {xp,n} == ZERO */
#endif
      cy += (rp[0]&1);
      mpn_rshift(rp, rp, n, 1);
      ASSERT (cy <= 2);
      hi = (cy<<(GMP_NUMB_BITS-1))&GMP_NUMB_MASK; /* (cy&1) << ... */
      cy >>= 1;
      /* We can have cy != 0 only if hi = 0... */
      ASSERT ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0);
      rp[n-1] |= hi;
      /* ... rp[n-1] + cy can not overflow, the following INCR is correct. */
#endif
      ASSERT (cy <= 1);
      /* Next increment can not overflow, read the previous comments about cy. */
      ASSERT ((cy == 0) || ((rp[n-1] & GMP_NUMB_HIGHBIT) == 0));
      MPN_INCR_U(rp, n, cy);

      /* Compute the highest half:
	 ([(xp + xm)/2 mod (B^n-1)] - xp ) * B^n
       */
      if (UNLIKELY (2*an < rn))
	{
	  /* Note that in this case, the only way the result can equal
	     zero mod B^{rn} - 1 is if the input is zero, and
	     then the output of both the recursive calls and this CRT
	     reconstruction is zero, not B^{rn} - 1. */
	  cy = mpn_sub_n (rp + n, rp, xp, 2*an - n);

	  /* FIXME: This subtraction of the high parts is not really
	     necessary, we do it to get the carry out, and for sanity
	     checking. */
	  cy = xp[n] + mpn_sub_nc (xp + 2*an - n, rp + 2*an - n,
				   xp + 2*an - n, rn - 2*an, cy);
	  ASSERT (mpn_zero_p (xp + 2*an - n+1, rn - 1 - 2*an));
	  cy = mpn_sub_1 (rp, rp, 2*an, cy);
	  ASSERT (cy == (xp + 2*an - n)[0]);
	}
      else
	{
	  cy = xp[n] + mpn_sub_n (rp + n, rp, xp, n);
	  /* cy = 1 only if {xp,n+1} is not ZERO, i.e. {rp,n} is not ZERO.
	     DECR will affect _at most_ the lowest n limbs. */
	  MPN_DECR_U (rp, 2*n, cy);
	}
#undef a0
#undef a1
#undef xp
#undef sp1
    }
}

// Assembly:
pushq %rbp
movq %rsp, %rbp
subq $0xd0, %rsp
movq %rdi, -0x8(%rbp)
movq %rsi, -0x10(%rbp)
movq %rdx, -0x18(%rbp)
movq %rcx, -0x20(%rbp)
movq %r8, -0x28(%rbp)
jmp 0x4ec11
jmp 0x4ec13
jmp 0x4ec15
movq -0x10(%rbp), %rax
andq $0x1, %rax
cmpq $0x0, %rax
jne 0x4ec2e
cmpq $0x16, -0x10(%rbp)
jge 0x4ed0c
movq -0x20(%rbp), %rax
cmpq -0x10(%rbp), %rax
setl %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4ecf2
movq -0x20(%rbp), %rax
shlq %rax
cmpq -0x10(%rbp), %rax
setle %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4ec8e
movq -0x8(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x392b0
jmp 0x4ecf0
movq -0x28(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x392b0
movq -0x8(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x10(%rbp), %rdx
movq -0x28(%rbp), %rcx
movq -0x10(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rcx
movq -0x20(%rbp), %r8
shlq %r8
subq -0x10(%rbp), %r8
callq 0x36b60
movq %rax, -0x30(%rbp)
movq -0x8(%rbp), %rax
movq -0x30(%rbp), %rcx
addq %rcx, (%rax)
jae 0x4ece6
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4ecdb
movq %rax, -0x38(%rbp)
jmp 0x4ecec
jmp 0x4ecee
jmp 0x4ecf0
jmp 0x4ed07
movq -0x8(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x10(%rbp), %rdx
movq -0x28(%rbp), %rcx
callq 0x4f280
jmp 0x4f26b
movq -0x10(%rbp), %rax
sarq %rax
movq %rax, -0x40(%rbp)
jmp 0x4ed19
movq -0x20(%rbp), %rax
cmpq -0x40(%rbp), %rax
setg %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4edad
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq %rax, -0x68(%rbp)
movq -0x28(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x28(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0x18(%rbp), %rcx
movq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rcx
movq -0x20(%rbp), %r8
subq -0x40(%rbp), %r8
callq 0x36b60
movq %rax, -0x48(%rbp)
movq -0x28(%rbp), %rax
movq -0x48(%rbp), %rcx
addq %rcx, (%rax)
jae 0x4ed9b
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4ed90
movq %rax, -0x70(%rbp)
jmp 0x4eda1
jmp 0x4eda3
movq -0x40(%rbp), %rax
movq %rax, -0x60(%rbp)
jmp 0x4edc5
movq -0x28(%rbp), %rax
movq %rax, -0x68(%rbp)
movq -0x18(%rbp), %rax
movq %rax, -0x58(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x60(%rbp)
movq -0x8(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq -0x58(%rbp), %rdx
movq -0x60(%rbp), %rcx
movq -0x68(%rbp), %r8
callq 0x4ebf0
movq -0x20(%rbp), %rax
cmpq -0x40(%rbp), %rax
setg %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4eeca
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
shlq %rcx
shlq $0x3, %rcx
addq %rcx, %rax
addq $0x10, %rax
movq %rax, -0x80(%rbp)
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rax
shlq %rax
shlq $0x3, %rax
addq %rax, %rdi
addq $0x10, %rdi
movq -0x18(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0x18(%rbp), %rcx
movq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rcx
movq -0x20(%rbp), %r8
subq -0x40(%rbp), %r8
callq 0x36d60
movq %rax, -0x48(%rbp)
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
shlq %rcx
shlq $0x3, %rcx
addq %rcx, %rax
movq -0x40(%rbp), %rcx
movq $0x0, 0x10(%rax,%rcx,8)
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
shlq %rcx
shlq $0x3, %rcx
addq %rcx, %rax
addq $0x10, %rax
movq -0x48(%rbp), %rcx
addq %rcx, (%rax)
jae 0x4eea6
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4ee9b
movq %rax, -0x90(%rbp)
jmp 0x4eeaf
jmp 0x4eeb1
movq -0x40(%rbp), %rax
movq -0x80(%rbp), %rcx
movq -0x40(%rbp), %rdx
addq (%rcx,%rdx,8), %rax
movq %rax, -0x88(%rbp)
jmp 0x4eedd
movq -0x18(%rbp), %rax
movq %rax, -0x80(%rbp)
movq -0x20(%rbp), %rax
movq %rax, -0x88(%rbp)
cmpq $0x28e, -0x40(%rbp)     # imm = 0x28E
jge 0x4eef0
movl $0x0, -0x74(%rbp)
jmp 0x4ef43
movq -0x40(%rbp), %rdi
movl $0x1, %esi
callq 0x56ab0
movl %eax, -0x74(%rbp)
movl -0x74(%rbp), %ecx
movl $0x1, %eax
shll %cl, %eax
subl $0x1, %eax
movl %eax, -0x94(%rbp)
movq -0x40(%rbp), %rax
movslq -0x94(%rbp), %rcx
andq %rcx, %rax
cmpq $0x0, %rax
je 0x4ef41
movl -0x74(%rbp), %eax
addl $-0x1, %eax
movl %eax, -0x74(%rbp)
movl -0x94(%rbp), %eax
sarl %eax
movl %eax, -0x94(%rbp)
jmp 0x4ef14
jmp 0x4ef43
cmpl $0x4, -0x74(%rbp)
jl 0x4ef86
movq -0x28(%rbp), %rdi
movq -0x40(%rbp), %rsi
movq -0x80(%rbp), %rdx
movq -0x88(%rbp), %rcx
movq -0x80(%rbp), %r8
movq -0x88(%rbp), %r9
movl -0x74(%rbp), %eax
movl %eax, (%rsp)
callq 0x56b70
movq %rax, %rdx
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
movq %rdx, (%rax,%rcx,8)
jmp 0x4f04f
movq -0x80(%rbp), %rax
cmpq -0x18(%rbp), %rax
sete %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4f038
jmp 0x4efaf
jmp 0x4efb1
jmp 0x4efb3
jmp 0x4efb5
movq -0x28(%rbp), %rdi
movq -0x18(%rbp), %rsi
movq -0x20(%rbp), %rdx
callq 0x392b0
movq -0x20(%rbp), %rax
shlq %rax
subq -0x40(%rbp), %rax
movq %rax, -0x88(%rbp)
movq -0x28(%rbp), %rdi
movq -0x28(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0x28(%rbp), %rcx
movq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rcx
movq -0x88(%rbp), %r8
callq 0x36d60
movq %rax, -0x48(%rbp)
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
movq $0x0, (%rax,%rcx,8)
movq -0x28(%rbp), %rax
movq -0x48(%rbp), %rcx
addq %rcx, (%rax)
jae 0x4f02b
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4f020
movq %rax, -0xa0(%rbp)
jmp 0x4f034
jmp 0x4f036
jmp 0x4f04d
movq -0x28(%rbp), %rdi
movq -0x80(%rbp), %rsi
movq -0x40(%rbp), %rdx
movq -0x28(%rbp), %rcx
callq 0x4f300
jmp 0x4f04f
movq -0x8(%rbp), %rdi
movq -0x8(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x40(%rbp), %rcx
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %r8
movq (%rax,%r8,8), %r8
callq 0x558e0
movq %rax, -0x48(%rbp)
movq -0x48(%rbp), %rax
shlq $0x3f, %rax
movq %rax, -0x50(%rbp)
movq $0x0, -0x48(%rbp)
movq -0x8(%rbp), %rax
movq -0x40(%rbp), %rcx
subq $0x1, %rcx
movq -0x48(%rbp), %rsi
movq -0x8(%rbp), %rdx
movq -0x40(%rbp), %rdi
subq $0x1, %rdi
movq (%rdx,%rdi,8), %rdx
movq -0x50(%rbp), %rdi
movq %rdi, -0xb8(%rbp)
addq -0xb8(%rbp), %rdx
adcq $0x0, %rsi
movq %rsi, -0x48(%rbp)
movq %rdx, (%rax,%rcx,8)
jmp 0x4f0c8
jmp 0x4f0ca
jmp 0x4f0cc
jmp 0x4f0ce
movq -0x8(%rbp), %rax
movq -0x48(%rbp), %rcx
addq %rcx, (%rax)
jae 0x4f0e6
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4f0db
movq %rax, -0xa8(%rbp)
jmp 0x4f0ef
jmp 0x4f0f1
movq -0x20(%rbp), %rax
shlq %rax
cmpq -0x10(%rbp), %rax
setl %al
andb $0x1, %al
movzbl %al, %eax
cmpl $0x0, %eax
setne %al
andb $0x1, %al
movzbl %al, %eax
cltq
cmpq $0x0, %rax
je 0x4f200
movq -0x8(%rbp), %rdi
movq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rdi
movq -0x8(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x20(%rbp), %rcx
shlq %rcx
subq -0x40(%rbp), %rcx
callq 0x36fe0
movq %rax, -0x48(%rbp)
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0xc0(%rbp)
movq -0x28(%rbp), %rdi
movq -0x20(%rbp), %rax
shlq %rax
shlq $0x3, %rax
addq %rax, %rdi
xorl %eax, %eax
subq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rdi
movq -0x8(%rbp), %rsi
movq -0x20(%rbp), %rax
shlq %rax
shlq $0x3, %rax
addq %rax, %rsi
xorl %eax, %eax
subq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rsi
movq -0x28(%rbp), %rdx
movq -0x20(%rbp), %rax
shlq %rax
shlq $0x3, %rax
addq %rax, %rdx
xorl %eax, %eax
subq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rdx
movq -0x10(%rbp), %rcx
movq -0x20(%rbp), %rax
shlq %rax
subq %rax, %rcx
movq -0x48(%rbp), %r8
callq 0x36fc0
movq %rax, %rcx
movq -0xc0(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x48(%rbp)
jmp 0x4f1e0
movq -0x8(%rbp), %rdi
movq -0x8(%rbp), %rsi
movq -0x20(%rbp), %rdx
shlq %rdx
movq -0x48(%rbp), %rcx
callq 0x36e60
movq %rax, -0x48(%rbp)
jmp 0x4f1fe
jmp 0x4f269
movq -0x28(%rbp), %rax
movq -0x40(%rbp), %rcx
movq (%rax,%rcx,8), %rax
movq %rax, -0xc8(%rbp)
movq -0x8(%rbp), %rdi
movq -0x40(%rbp), %rax
shlq $0x3, %rax
addq %rax, %rdi
movq -0x8(%rbp), %rsi
movq -0x28(%rbp), %rdx
movq -0x40(%rbp), %rcx
callq 0x36fe0
movq %rax, %rcx
movq -0xc8(%rbp), %rax
addq %rcx, %rax
movq %rax, -0x48(%rbp)
movq -0x8(%rbp), %rax
movq -0x48(%rbp), %rcx
subq %rcx, (%rax)
jae 0x4f25c
subq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x4f251
movq %rax, -0xb0(%rbp)
jmp 0x4f265
jmp 0x4f267
jmp 0x4f269
jmp 0x4f26b
addq $0xd0, %rsp
popq %rbp
retq
nopw %cs:(%rax,%rax)