// File: /workspace/github_cpp_makefile_star2_O2/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
pushq %r15
pushq %r14
pushq %r13
pushq %r12
pushq %rbx
subq $0x38, %rsp
movq %r8, %r15
movq %rcx, 0x8(%rsp)
movq %rsi, %r14
movq %rdi, 0x10(%rsp)
testb $0x1, %r14b
sete %al
cmpq $0x16, %rsi
setge %cl
testb %al, %cl
je 0x2553e
movq %r14, %r13
shrq %r13
movq 0x8(%rsp), %rbx
leaq (%r15,%r13,8), %rbp
subq %r13, %rbx
movq %rdx, 0x20(%rsp)
movq %rbp, 0x18(%rsp)
jle 0x2568b
leaq (%rdx,%r13,8), %rcx
movq %rcx, 0x28(%rsp)
movq %r15, %rdi
movq %rdx, %rsi
movq %r13, %rdx
movq %rbx, %r8
callq 0x17c54
movq %r15, %rcx
addq %rax, (%rcx)
jae 0x254b7
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x254ac
movq 0x10(%rsp), %rdi
movq %r13, %rsi
movq %r15, %rdx
movq %r13, %rcx
movq %rbp, %r8
callq 0x25434
leaq (%r15,%r14,8), %r12
leaq (%r15,%r14,8), %rbp
addq $0x10, %rbp
movq %rbp, %rdi
movq 0x20(%rsp), %rsi
movq %r13, %rdx
movq 0x28(%rsp), %rcx
movq %rbx, %r8
callq 0x17dc8
andq $0x0, 0x10(%r12,%r13,8)
movq %rbp, %rcx
addq %rax, (%rcx)
jae 0x2550a
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x254ff
movq 0x10(%r12,%r13,8), %r12
addq %r13, %r12
cmpq $0x51b, %r14            # imm = 0x51B
jb 0x255a8
pushq $0x1
popq %rsi
movq %r13, %rdi
callq 0x2a2c8
pushq $-0x1
popq %rdx
movl %eax, %ecx
shll %cl, %edx
notl %edx
testl %edx, %r13d
je 0x25583
decl %eax
shrl %edx
jmp 0x25533
cmpq %r14, 0x8(%rsp)
jl 0x256ab
movq %r15, %rdi
movq %rdx, %rsi
movq %r14, %rdx
callq 0x196c0
leaq (%r15,%r14,8), %rdx
movq 0x10(%rsp), %rbx
movq %rbx, %rdi
movq %r15, %rsi
movq %r14, %rcx
callq 0x17cf0
addq %rax, (%rbx)
jae 0x2557e
addq $0x1, 0x8(%rbx)
leaq 0x8(%rbx), %rbx
jb 0x25573
jmp 0x2567c
cmpl $0x4, %eax
jl 0x255a8
movl %eax, (%rsp)
movq %r15, %rdi
movq %r13, %rsi
movq %rbp, %rdx
movq %r12, %rcx
movq %rbp, %r8
movq %r12, %r9
callq 0x2a311
movq %rax, (%r15,%r13,8)
jmp 0x255f7
movq 0x20(%rsp), %rsi
cmpq %rsi, %rbp
je 0x25762
leaq 0x1(%r13), %rdx
movq %r15, %rdi
movq %rbp, %rsi
callq 0x196c0
movq (%r15,%r14,8), %rbx
movq %r15, %rdi
movq %r15, %rsi
movq 0x18(%rsp), %rdx
movq %r13, %rcx
callq 0x17ed0
andq $0x0, (%r15,%r13,8)
addq %rbx, %rax
movq %r15, %rcx
addq %rax, (%rcx)
jae 0x255f7
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x255ec
movq (%r15,%r13,8), %r8
movq 0x10(%rsp), %rbx
movq %rbx, %rdi
movq %rbx, %rsi
movq %r15, %rdx
movq %r13, %rcx
callq 0x294e0
shlq $0x3f, %rax
leaq (%rbx,%r13,8), %rdi
movq -0x8(%rdi), %rcx
movq %rax, 0x30(%rsp)
xorl %eax, %eax
addq 0x30(%rsp), %rcx
adcq $0x0, %rax
movq %rcx, -0x8(%rdi)
addq %rax, (%rbx)
jae 0x25641
addq $0x1, 0x8(%rbx)
leaq 0x8(%rbx), %rbx
jb 0x25636
movq 0x8(%rsp), %rax
addq %rax, %rax
subq %rax, %r14
jg 0x256fc
movq (%r15,%r13,8), %rbx
movq 0x10(%rsp), %r14
movq %r14, %rsi
movq %r15, %rdx
movq %r13, %rcx
callq 0x17ed0
addq %rbx, %rax
subq %rax, (%r14)
jae 0x2567c
subq $0x1, 0x8(%r14)
leaq 0x8(%r14), %r14
jb 0x25671
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq 0x10(%rsp), %rdi
movq %r13, %rsi
movq %rdx, %rbp
movq 0x8(%rsp), %r12
movq %r12, %rcx
movq %r15, %r8
callq 0x25434
jmp 0x25512
movq 0x8(%rsp), %rax
leaq (%rax,%rax), %rbx
subq %r14, %rbx
jle 0x257a9
movq %r15, %rdi
movq %rdx, %rsi
movq 0x8(%rsp), %rdx
callq 0x196c0
leaq (%r15,%r14,8), %rcx
movq 0x10(%rsp), %r12
movq %r12, %rdi
movq %r15, %rsi
movq %r14, %rdx
movq %rbx, %r8
callq 0x17c54
addq %rax, (%r12)
jae 0x256fa
addq $0x1, 0x8(%r12)
leaq 0x8(%r12), %r12
jb 0x256ed
jmp 0x2567c
movq %rax, %r12
movq %rax, %rcx
subq %r13, %rcx
movq 0x10(%rsp), %rbp
movq %rbp, %rsi
movq %r15, %rdx
callq 0x17ed0
movq (%r15,%r13,8), %rbx
shlq $0x3, %r13
leaq (%r15,%r12,8), %rdi
subq %r13, %rdi
leaq (,%r12,8), %rsi
addq %rbp, %rsi
subq %r13, %rsi
movq %rdi, %rdx
movq %r14, %rcx
movq %rax, %r8
callq 0x17eb0
addq %rax, %rbx
movq %rbp, %rdi
movq %rbp, %rsi
movq %r12, %rdx
movq %rbx, %rcx
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x17e44
movq %r15, %rdi
movq 0x8(%rsp), %rbx
movq %rbx, %rdx
callq 0x196c0
leaq (%rbx,%rbx), %r8
subq %r13, %r8
movq %r15, %rdi
movq %r15, %rsi
movq %r13, %rdx
movq 0x18(%rsp), %rcx
callq 0x17dc8
andq $0x0, (%r15,%r13,8)
movq %r15, %rcx
addq %rax, (%rcx)
jae 0x257a4
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x25799
jmp 0x255f7
movq 0x10(%rsp), %rdi
movq %rdx, %rsi
movq 0x8(%rsp), %rdx
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x196c0