(root)/
gmp-6.3.0/
tune/
modlinv.c
       1  /* Alternate implementations of binvert_limb to compare speeds. */
       2  
       3  /*
       4  Copyright 2000, 2002 Free Software Foundation, Inc.
       5  
       6  This file is part of the GNU MP Library.
       7  
       8  The GNU MP Library is free software; you can redistribute it and/or modify
       9  it under the terms of either:
      10  
      11    * the GNU Lesser General Public License as published by the Free
      12      Software Foundation; either version 3 of the License, or (at your
      13      option) any later version.
      14  
      15  or
      16  
      17    * the GNU General Public License as published by the Free Software
      18      Foundation; either version 2 of the License, or (at your option) any
      19      later version.
      20  
      21  or both in parallel, as here.
      22  
      23  The GNU MP Library is distributed in the hope that it will be useful, but
      24  WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
      25  or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License
      26  for more details.
      27  
      28  You should have received copies of the GNU General Public License and the
      29  GNU Lesser General Public License along with the GNU MP Library.  If not,
      30  see https://www.gnu.org/licenses/.  */
      31  
      32  #include <stdio.h>
      33  #include "gmp-impl.h"
      34  #include "longlong.h"
      35  #include "speed.h"
      36  
      37  
      38  /* Like the standard version in gmp-impl.h, but with the expressions using a
      39     "1-" form.  This has the same number of steps, but "1-" is on the
      40     dependent chain, whereas the "2*" in the standard version isn't.
      41     Depending on the CPU this should be the same or a touch slower.  */
      42  
      43  #if GMP_LIMB_BITS <= 32
      44  #define binvert_limb_mul1(inv,n)                                \
      45    do {                                                          \
      46      mp_limb_t  __n = (n);                                       \
      47      mp_limb_t  __inv;                                           \
      48      ASSERT ((__n & 1) == 1);                                    \
      49      __inv = binvert_limb_table[(__n&0xFF)/2]; /*  8 */          \
      50      __inv = (1 - __n * __inv) * __inv + __inv;  /* 16 */        \
      51      __inv = (1 - __n * __inv) * __inv + __inv;  /* 32 */        \
      52      ASSERT (__inv * __n == 1);                                  \
      53      (inv) = __inv;                                              \
      54    } while (0)
      55  #endif
      56  
      57  #if GMP_LIMB_BITS > 32 && GMP_LIMB_BITS <= 64
      58  #define binvert_limb_mul1(inv,n)                                \
      59    do {                                                          \
      60      mp_limb_t  __n = (n);                                       \
      61      mp_limb_t  __inv;                                           \
      62      ASSERT ((__n & 1) == 1);                                    \
      63      __inv = binvert_limb_table[(__n&0xFF)/2]; /*  8 */          \
      64      __inv = (1 - __n * __inv) * __inv + __inv;  /* 16 */        \
      65      __inv = (1 - __n * __inv) * __inv + __inv;  /* 32 */        \
      66      __inv = (1 - __n * __inv) * __inv + __inv;  /* 64 */        \
      67      ASSERT (__inv * __n == 1);                                  \
      68      (inv) = __inv;                                              \
      69    } while (0)
      70  #endif
      71  
      72  
      73  /* The loop based version used in GMP 3.0 and earlier.  Usually slower than
      74     multiplying, due to the number of steps that must be performed.  Much
      75     slower when the processor has a good multiply.  */
      76  
      77  #define binvert_limb_loop(inv,n)                \
      78    do {                                          \
      79      mp_limb_t  __v = (n);                       \
      80      mp_limb_t  __v_orig = __v;                  \
      81      mp_limb_t  __make_zero = 1;                 \
      82      mp_limb_t  __two_i = 1;                     \
      83      mp_limb_t  __v_inv = 0;                     \
      84                                                  \
      85      ASSERT ((__v & 1) == 1);                    \
      86                                                  \
      87      do                                          \
      88        {                                         \
      89          while ((__two_i & __make_zero) == 0)    \
      90            __two_i <<= 1, __v <<= 1;             \
      91          __v_inv += __two_i;                     \
      92          __make_zero -= __v;                     \
      93        }                                         \
      94      while (__make_zero);                        \
      95                                                  \
      96      ASSERT (__v_orig * __v_inv == 1);           \
      97      (inv) = __v_inv;                            \
      98    } while (0)
      99  
     100  
     101  /* Another loop based version with conditionals, but doing a fixed number of
     102     steps. */
     103  
     104  #define binvert_limb_cond(inv,n)                \
     105    do {                                          \
     106      mp_limb_t  __n = (n);                       \
     107      mp_limb_t  __rem = (1 - __n) >> 1;          \
     108      mp_limb_t  __inv = GMP_LIMB_HIGHBIT;        \
     109      int        __count;                         \
     110                                                  \
     111      ASSERT ((__n & 1) == 1);                    \
     112                                                  \
     113      __count = GMP_LIMB_BITS-1;               \
     114      do                                          \
     115        {                                         \
     116          __inv >>= 1;                            \
     117          if (__rem & 1)                          \
     118            {                                     \
     119              __inv |= GMP_LIMB_HIGHBIT;          \
     120              __rem -= __n;                       \
     121            }                                     \
     122          __rem >>= 1;                            \
     123        }                                         \
     124      while (-- __count);                         \
     125                                                  \
     126      ASSERT (__inv * __n == 1);                  \
     127      (inv) = __inv;                              \
     128    } while (0)
     129  
     130  
     131  /* Another loop based bitwise version, but purely arithmetic, no
     132     conditionals. */
     133  
     134  #define binvert_limb_arith(inv,n)                                       \
     135    do {                                                                  \
     136      mp_limb_t  __n = (n);                                               \
     137      mp_limb_t  __rem = (1 - __n) >> 1;                                  \
     138      mp_limb_t  __inv = GMP_LIMB_HIGHBIT;                                \
     139      mp_limb_t  __lowbit;                                                \
     140      int        __count;                                                 \
     141                                                                          \
     142      ASSERT ((__n & 1) == 1);                                            \
     143                                                                          \
     144      __count = GMP_LIMB_BITS-1;                                       \
     145      do                                                                  \
     146        {                                                                 \
     147          __lowbit = __rem & 1;                                           \
     148          __inv = (__inv >> 1) | (__lowbit << (GMP_LIMB_BITS-1));      \
     149          __rem = (__rem - (__n & -__lowbit)) >> 1;                       \
     150        }                                                                 \
     151      while (-- __count);                                                 \
     152                                                                          \
     153      ASSERT (__inv * __n == 1);                                          \
     154      (inv) = __inv;                                                      \
     155    } while (0)
     156  
     157  
     158  double
     159  speed_binvert_limb_mul1 (struct speed_params *s)
     160  {
     161    SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_mul1);
     162  }
     163  double
     164  speed_binvert_limb_loop (struct speed_params *s)
     165  {
     166    SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_loop);
     167  }
     168  double
     169  speed_binvert_limb_cond (struct speed_params *s)
     170  {
     171    SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_cond);
     172  }
     173  double
     174  speed_binvert_limb_arith (struct speed_params *s)
     175  {
     176    SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_arith);
     177  }