// File: /workspace/github_cpp_makefile_star2_O1/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, %r12
movq %rcx, %rbx
movq %rdx, %rbp
movq %rsi, %r15
movq %rdi, %r14
testb $0x1, %r15b
sete %al
cmpq $0x16, %rsi
setge %cl
testb %al, %cl
je 0x2aff7
movq %r15, %r13
shrq %r13
leaq (%r12,%r13,8), %rax
movq %rax, 0x18(%rsp)
cmpq %r13, %rbx
movq %r14, 0x28(%rsp)
movq %rbx, 0x10(%rsp)
jle 0x2b257
leaq (,%r13,8), %rdx
addq %rbp, %rdx
subq %r13, %rbx
movq %rdx, 0x20(%rsp)
je 0x2b035
movq %r12, %rdi
movq %rbp, %rsi
movq %rbx, %rcx
callq 0x1bfa0
movq %rbx, %rcx
testq %rax, %rax
je 0x2b037
movq %rbx, %rax
cmpq %r13, %rax
jge 0x2b05f
movq (%rbp,%rax,8), %rdx
leaq 0x1(%rax), %rcx
incq %rdx
movq %rdx, (%r12,%rax,8)
movq %rcx, %rax
je 0x2afdb
jmp 0x2b037
cmpq %r15, %rbx
jl 0x2b273
movq %r12, %rdi
movq %rbp, %rsi
movq %r15, %rdx
callq 0x1da3c
leaq (%r12,%r15,8), %rdx
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rcx
callq 0x1bfa0
addq %rax, (%r14)
jae 0x2b030
addq $0x1, 0x8(%r14)
leaq 0x8(%r14), %r14
jb 0x2b025
jmp 0x2b248
xorl %ecx, %ecx
cmpq %rbp, %r12
setne %al
cmpq %r13, %rcx
setl %dl
andb %al, %dl
xorl %eax, %eax
cmpb $0x1, %dl
jne 0x2b064
movq (%rbp,%rcx,8), %rdx
movq %rdx, (%r12,%rcx,8)
incq %rcx
cmpq %rcx, %r13
jne 0x2b04c
jmp 0x2b064
movl $0x1, %eax
movq %r12, %rcx
addq %rax, (%rcx)
jae 0x2b077
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x2b06c
movq %r14, %rdi
movq %r13, %rsi
movq %r12, %rdx
movq %r13, %rcx
movq 0x18(%rsp), %r8
callq 0x2af5c
leaq (%r12,%r15,8), %r14
addq $0x10, %r14
testq %rbx, %rbx
je 0x2b0cf
movq %r14, %rdi
movq %rbp, %rsi
movq 0x20(%rsp), %rdx
movq %rbx, %rcx
callq 0x1c1c0
testq %rax, %rax
je 0x2b0d3
cmpq %r13, %rbx
jge 0x2b0fe
movq (%rbp,%rbx,8), %rcx
leaq 0x1(%rbx), %rax
subq $0x1, %rcx
movq %rcx, (%r14,%rbx,8)
movq %rax, %rbx
jb 0x2b0b2
jmp 0x2b0d6
xorl %eax, %eax
jmp 0x2b0d6
movq %rbx, %rax
cmpq %rbp, %r14
setne %cl
cmpq %r13, %rax
setl %dl
andb %cl, %dl
xorl %ecx, %ecx
cmpb $0x1, %dl
jne 0x2b103
movq (%rbp,%rax,8), %rdx
movq %rdx, (%r14,%rax,8)
incq %rax
cmpq %rax, %r13
jne 0x2b0eb
jmp 0x2b103
movl $0x1, %ecx
movq $0x0, (%r14,%r13,8)
movq %r14, %rax
addq %rcx, (%rax)
jae 0x2b11e
addq $0x1, 0x8(%rax)
leaq 0x8(%rax), %rax
jb 0x2b113
movq (%r14,%r13,8), %rbx
addq %r13, %rbx
xorl %eax, %eax
cmpq $0x51b, %r15            # imm = 0x51B
jb 0x2b153
movq %r13, %rdi
movl $0x1, %esi
callq 0x306a8
movl $0xffffffff, %edx       # imm = 0xFFFFFFFF
movl %eax, %ecx
shll %cl, %edx
notl %edx
testl %edx, %r13d
je 0x2b153
decl %eax
shrl %edx
jmp 0x2b148
cmpl $0x4, %eax
jl 0x2b178
movl %eax, (%rsp)
movq %r12, %rdi
movq %r13, %rsi
movq %r14, %rdx
movq %rbx, %rcx
movq %r14, %r8
movq %rbx, %r9
callq 0x306f1
movq %rax, (%r12,%r13,8)
jmp 0x2b1c5
cmpq %rbp, %r14
je 0x2b321
leaq 0x1(%r13), %rdx
movq %r12, %rdi
movq %r14, %rsi
callq 0x1da3c
movq (%r12,%r15,8), %rbx
movq %r12, %rdi
movq %r12, %rsi
movq 0x18(%rsp), %rdx
movq %r13, %rcx
callq 0x1c1c0
addq %rbx, %rax
movq $0x0, (%r12,%r13,8)
movq %r12, %rcx
addq %rax, (%rcx)
jae 0x2b1c5
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x2b1ba
movq 0x10(%rsp), %rbx
movq (%r12,%r13,8), %r8
movq 0x28(%rsp), %r14
movq %r14, %rdi
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x2f8e0
shlq $0x3f, %rax
leaq (%r14,%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)
movq %r14, %rcx
addq %rax, (%rcx)
jae 0x2b217
addq $0x1, 0x8(%rcx)
leaq 0x8(%rcx), %rcx
jb 0x2b20c
addq %rbx, %rbx
subq %rbx, %r15
jg 0x2b2b4
movq (%r12,%r13,8), %rbx
movq %r14, %rsi
movq %r12, %rdx
movq %r13, %rcx
callq 0x1c1c0
addq %rbx, %rax
subq %rax, (%r14)
jae 0x2b248
subq $0x1, 0x8(%r14)
leaq 0x8(%r14), %r14
jb 0x2b23d
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
retq
movq %r14, %rdi
movq %r13, %rsi
movq %rbp, %rdx
movq %rbx, %rcx
movq %r12, %r8
callq 0x2af5c
movq %rbp, %r14
jmp 0x2b125
movq %rbx, %rdx
addq %rbx, %rbx
subq %r15, %rbx
jle 0x2b33c
movq %r12, %rdi
movq %rbp, %rsi
callq 0x1da3c
leaq (%r12,%r15,8), %rcx
movq %r14, %rdi
movq %r12, %rsi
movq %r15, %rdx
movq %rbx, %r8
callq 0x301cc
addq %rax, (%r14)
jae 0x2b2b2
addq $0x1, 0x8(%r14)
leaq 0x8(%r14), %r14
jb 0x2b2a7
jmp 0x2b248
movq %rbx, %rcx
subq %r13, %rcx
movq %r14, %rsi
movq %r12, %rdx
callq 0x1c1c0
movq %rbx, %rbp
movq (%r12,%r13,8), %rbx
shlq $0x3, %r13
leaq (%r12,%rbp,8), %rdi
subq %r13, %rdi
leaq (%r14,%rbp,8), %rsi
subq %r13, %rsi
movq %rdi, %rdx
movq %r15, %rcx
movq %rax, %r8
callq 0x1c1a0
addq %rbx, %rax
subq %rax, (%r14)
jae 0x2b248
movq %rbp, %rcx
cmpq $0x2, %rbp
movl $0x1, %eax
cmovlq %rax, %rcx
cmpq %rax, %rcx
je 0x2b248
subq $0x1, (%r14,%rax,8)
leaq 0x1(%rax), %rax
jb 0x2b308
jmp 0x2b248
movq %r12, %rdi
movq %rbp, %rsi
movq 0x10(%rsp), %rbx
movq %rbx, %rdx
movq %r13, %rcx
callq 0x73da
jmp 0x2b1ca
movq %r14, %rdi
movq %rbp, %rsi
addq $0x38, %rsp
popq %rbx
popq %r12
popq %r13
popq %r14
popq %r15
popq %rbp
jmp 0x1da3c