gcd_22

Torbjörn Granlund tg at gmplib.org
Tue Aug 27 14:35:45 UTC 2019


I got something working.  It runs quite well, and seems to beat the
performance of mpn_gcd.  Here is the code:

#include "gmp-impl.h"
#include "longlong.h"

#ifndef CMP_SWAP
#define CMP_SWAP(ap,bp,n)						\
  do {									\
    if (ap[n - 1] < bp[n - 1])						\
      {									\
	mp_limb_t *_tp = ap; ap = bp; bp = _tp;				\
      }									\
  } while (0)
#endif
// We should do CMP_SWAP something like this:
// cmp
// mov up, tmp
// cmov vp, up
// cmov tmp, vp

#define SMASH(a,b) a##b

void mpn_gcd_33 (mp_limb_t *, mp_limb_t *, mp_limb_t *);
void mpn_gcd_44 (mp_limb_t *, mp_limb_t *, mp_limb_t *);
void mpn_gcd_55 (mp_limb_t *, mp_limb_t *, mp_limb_t *);

mp_limb_t mpn_sub_3 (mp_ptr, mp_srcptr, mp_srcptr);
mp_limb_t mpn_rshift_3 (mp_ptr, mp_srcptr, int);

static inline void
mpn_gcd_NN (mp_limb_t *rp, mp_limb_t *up, mp_limb_t *vp, size_t N)
{
  mp_limb_t cy;

  do
    {
      // Conditionally swap U and V.  This must be done without jumps.
      CMP_SWAP(up,vp,N);

#if HAVE_NATIVE_mpn_sub_3
      cy = mpn_sub_3 (up, up, vp);
#else
      cy = mpn_sub_n (up, up, vp, N);
#endif
      if (UNLIKELY (cy))
	mpn_neg (up, up, N);

      if (UNLIKELY (up[0] == 0))
	{
	  // Handle any number of low U zeros including that U = 0
	  int all_zeros = 1;
	  mp_size_t i;
	  for (i = 1; i < N && all_zeros; i++)
	    all_zeros = (up[i] == 0);

	  if (all_zeros)
	    {
	      mpn_copyi (rp, vp, N);
	      return;
	    }
	  mpn_copyi (up, up + (i - 1), N - (i - 1));
	  mpn_zero (up + N - (i - 1), i - 1);
	}
      int cnt;
      count_trailing_zeros (cnt, up[0]);
#if HAVE_NATIVE_mpn_rshift_3
      mpn_rshift_3 (up, up, cnt);
#else
      mpn_rshift (up, up, N, cnt);
#endif
    }
  while ((up[N - 1] | vp[N - 1]) != 0);

  switch (N)
    {
    case 3:
      {
	mp_double_limb_t g = mpn_gcd_22 (up[1], up[0], vp[1], vp[0]);
	rp[0] = g.d0;
	rp[1] = g.d1;
	rp[2] = 0;
	break;
      }
    case 4:
      mpn_gcd_33 (rp, up, vp);
      rp[3] = 0;
      break;
    case 5:
      mpn_gcd_44 (rp, up, vp);
      rp[4] = 0;
      break;
    }
}

void
SMASH(mpn_gcd_,33) (mp_limb_t *rp, mp_limb_t *up, mp_limb_t *vp)
{
  mpn_gcd_NN (rp, up, vp, 3);
}

void
SMASH(mpn_gcd_,44) (mp_limb_t *rp, mp_limb_t *up, mp_limb_t *vp)
{
  mpn_gcd_NN (rp, up, vp, 4);
}

void
SMASH(mpn_gcd_,55) (mp_limb_t *rp, mp_limb_t *up, mp_limb_t *vp)
{
  mpn_gcd_NN (rp, up, vp, 5);
}

-- 
Torbjörn
Please encrypt, key id 0xC8601622


More information about the gmp-devel mailing list