Home | History | Annotate | Line # | Download | only in tune
      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 }
    178