github.com/aergoio/aergo@v1.3.1/libtool/src/gmp-6.1.2/tune/modlinv.c (about) 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.h" 34 #include "gmp-impl.h" 35 #include "longlong.h" 36 #include "speed.h" 37 38 39 /* Like the standard version in gmp-impl.h, but with the expressions using a 40 "1-" form. This has the same number of steps, but "1-" is on the 41 dependent chain, whereas the "2*" in the standard version isn't. 42 Depending on the CPU this should be the same or a touch slower. */ 43 44 #if GMP_LIMB_BITS <= 32 45 #define binvert_limb_mul1(inv,n) \ 46 do { \ 47 mp_limb_t __n = (n); \ 48 mp_limb_t __inv; \ 49 ASSERT ((__n & 1) == 1); \ 50 __inv = binvert_limb_table[(__n&0xFF)/2]; /* 8 */ \ 51 __inv = (1 - __n * __inv) * __inv + __inv; /* 16 */ \ 52 __inv = (1 - __n * __inv) * __inv + __inv; /* 32 */ \ 53 ASSERT (__inv * __n == 1); \ 54 (inv) = __inv; \ 55 } while (0) 56 #endif 57 58 #if GMP_LIMB_BITS > 32 && GMP_LIMB_BITS <= 64 59 #define binvert_limb_mul1(inv,n) \ 60 do { \ 61 mp_limb_t __n = (n); \ 62 mp_limb_t __inv; \ 63 ASSERT ((__n & 1) == 1); \ 64 __inv = binvert_limb_table[(__n&0xFF)/2]; /* 8 */ \ 65 __inv = (1 - __n * __inv) * __inv + __inv; /* 16 */ \ 66 __inv = (1 - __n * __inv) * __inv + __inv; /* 32 */ \ 67 __inv = (1 - __n * __inv) * __inv + __inv; /* 64 */ \ 68 ASSERT (__inv * __n == 1); \ 69 (inv) = __inv; \ 70 } while (0) 71 #endif 72 73 74 /* The loop based version used in GMP 3.0 and earlier. Usually slower than 75 multiplying, due to the number of steps that must be performed. Much 76 slower when the processor has a good multiply. */ 77 78 #define binvert_limb_loop(inv,n) \ 79 do { \ 80 mp_limb_t __v = (n); \ 81 mp_limb_t __v_orig = __v; \ 82 mp_limb_t __make_zero = 1; \ 83 mp_limb_t __two_i = 1; \ 84 mp_limb_t __v_inv = 0; \ 85 \ 86 ASSERT ((__v & 1) == 1); \ 87 \ 88 do \ 89 { \ 90 while ((__two_i & __make_zero) == 0) \ 91 __two_i <<= 1, __v <<= 1; \ 92 __v_inv += __two_i; \ 93 __make_zero -= __v; \ 94 } \ 95 while (__make_zero); \ 96 \ 97 ASSERT (__v_orig * __v_inv == 1); \ 98 (inv) = __v_inv; \ 99 } while (0) 100 101 102 /* Another loop based version with conditionals, but doing a fixed number of 103 steps. */ 104 105 #define binvert_limb_cond(inv,n) \ 106 do { \ 107 mp_limb_t __n = (n); \ 108 mp_limb_t __rem = (1 - __n) >> 1; \ 109 mp_limb_t __inv = GMP_LIMB_HIGHBIT; \ 110 int __count; \ 111 \ 112 ASSERT ((__n & 1) == 1); \ 113 \ 114 __count = GMP_LIMB_BITS-1; \ 115 do \ 116 { \ 117 __inv >>= 1; \ 118 if (__rem & 1) \ 119 { \ 120 __inv |= GMP_LIMB_HIGHBIT; \ 121 __rem -= __n; \ 122 } \ 123 __rem >>= 1; \ 124 } \ 125 while (-- __count); \ 126 \ 127 ASSERT (__inv * __n == 1); \ 128 (inv) = __inv; \ 129 } while (0) 130 131 132 /* Another loop based bitwise version, but purely arithmetic, no 133 conditionals. */ 134 135 #define binvert_limb_arith(inv,n) \ 136 do { \ 137 mp_limb_t __n = (n); \ 138 mp_limb_t __rem = (1 - __n) >> 1; \ 139 mp_limb_t __inv = GMP_LIMB_HIGHBIT; \ 140 mp_limb_t __lowbit; \ 141 int __count; \ 142 \ 143 ASSERT ((__n & 1) == 1); \ 144 \ 145 __count = GMP_LIMB_BITS-1; \ 146 do \ 147 { \ 148 __lowbit = __rem & 1; \ 149 __inv = (__inv >> 1) | (__lowbit << (GMP_LIMB_BITS-1)); \ 150 __rem = (__rem - (__n & -__lowbit)) >> 1; \ 151 } \ 152 while (-- __count); \ 153 \ 154 ASSERT (__inv * __n == 1); \ 155 (inv) = __inv; \ 156 } while (0) 157 158 159 double 160 speed_binvert_limb_mul1 (struct speed_params *s) 161 { 162 SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_mul1); 163 } 164 double 165 speed_binvert_limb_loop (struct speed_params *s) 166 { 167 SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_loop); 168 } 169 double 170 speed_binvert_limb_cond (struct speed_params *s) 171 { 172 SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_cond); 173 } 174 double 175 speed_binvert_limb_arith (struct speed_params *s) 176 { 177 SPEED_ROUTINE_MODLIMB_INVERT (binvert_limb_arith); 178 }