Line | Count | Source (jump to first uncovered line) |
1 | | /* mpn_gcd_22 -- double limb greatest common divisor. |
2 | | |
3 | | Copyright 1994, 1996, 2000, 2001, 2009, 2012, 2019 Free Software Foundation, Inc. |
4 | | |
5 | | This file is part of the GNU MP Library. |
6 | | |
7 | | The GNU MP Library is free software; you can redistribute it and/or modify |
8 | | it under the terms of either: |
9 | | |
10 | | * the GNU Lesser General Public License as published by the Free |
11 | | Software Foundation; either version 3 of the License, or (at your |
12 | | option) any later version. |
13 | | |
14 | | or |
15 | | |
16 | | * the GNU General Public License as published by the Free Software |
17 | | Foundation; either version 2 of the License, or (at your option) any |
18 | | later version. |
19 | | |
20 | | or both in parallel, as here. |
21 | | |
22 | | The GNU MP Library is distributed in the hope that it will be useful, but |
23 | | WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY |
24 | | or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License |
25 | | for more details. |
26 | | |
27 | | You should have received copies of the GNU General Public License and the |
28 | | GNU Lesser General Public License along with the GNU MP Library. If not, |
29 | | see https://www.gnu.org/licenses/. */ |
30 | | |
31 | | #include "gmp-impl.h" |
32 | | #include "longlong.h" |
33 | | |
34 | | #if GMP_NAIL_BITS > 0 |
35 | | #error Nails not supported. |
36 | | #endif |
37 | | |
38 | | mp_double_limb_t |
39 | | mpn_gcd_22 (mp_limb_t u1, mp_limb_t u0, mp_limb_t v1, mp_limb_t v0) |
40 | 0 | { |
41 | 0 | mp_double_limb_t g; |
42 | 0 | ASSERT (u0 & v0 & 1); |
43 | | |
44 | | /* Implicit least significant bit */ |
45 | 0 | u0 = (u0 >> 1) | (u1 << (GMP_LIMB_BITS - 1)); |
46 | 0 | u1 >>= 1; |
47 | |
|
48 | 0 | v0 = (v0 >> 1) | (v1 << (GMP_LIMB_BITS - 1)); |
49 | 0 | v1 >>= 1; |
50 | |
|
51 | 0 | while (u1 || v1) /* u1 == 0 can happen at most twice per call */ |
52 | 0 | { |
53 | 0 | mp_limb_t vgtu, t1, t0; |
54 | 0 | sub_ddmmss (t1, t0, u1, u0, v1, v0); |
55 | 0 | vgtu = LIMB_HIGHBIT_TO_MASK(t1); |
56 | |
|
57 | 0 | if (UNLIKELY (t0 == 0)) |
58 | 0 | { |
59 | 0 | if (t1 == 0) |
60 | 0 | { |
61 | 0 | g.d1 = (u1 << 1) | (u0 >> (GMP_LIMB_BITS - 1)); |
62 | 0 | g.d0 = (u0 << 1) | 1; |
63 | 0 | return g; |
64 | 0 | } |
65 | 0 | int c; |
66 | 0 | count_trailing_zeros (c, t1); |
67 | | |
68 | | /* v1 = min (u1, v1) */ |
69 | 0 | v1 += (vgtu & t1); |
70 | | /* u0 = |u1 - v1| */ |
71 | 0 | u0 = (t1 ^ vgtu) - vgtu; |
72 | 0 | ASSERT (c < GMP_LIMB_BITS - 1); |
73 | 0 | u0 >>= c + 1; |
74 | 0 | u1 = 0; |
75 | 0 | } |
76 | 0 | else |
77 | 0 | { |
78 | 0 | int c; |
79 | 0 | count_trailing_zeros (c, t0); |
80 | 0 | c++; |
81 | | /* V <-- min (U, V). |
82 | | |
83 | | Assembly version should use cmov. Another alternative, |
84 | | avoiding carry propagation, would be |
85 | | |
86 | | v0 += vgtu & t0; v1 += vtgu & (u1 - v1); |
87 | | */ |
88 | 0 | add_ssaaaa (v1, v0, v1, v0, vgtu & t1, vgtu & t0); |
89 | | /* U <-- |U - V| |
90 | | No carry handling needed in this conditional negation, |
91 | | since t0 != 0. */ |
92 | 0 | u0 = (t0 ^ vgtu) - vgtu; |
93 | 0 | u1 = t1 ^ vgtu; |
94 | 0 | if (UNLIKELY (c == GMP_LIMB_BITS)) |
95 | 0 | { |
96 | 0 | u0 = u1; |
97 | 0 | u1 = 0; |
98 | 0 | } |
99 | 0 | else |
100 | 0 | { |
101 | 0 | u0 = (u0 >> c) | (u1 << (GMP_LIMB_BITS - c)); |
102 | 0 | u1 >>= c; |
103 | 0 | } |
104 | 0 | } |
105 | 0 | } |
106 | 0 | while ((v0 | u0) & GMP_LIMB_HIGHBIT) |
107 | 0 | { /* At most two iterations */ |
108 | 0 | mp_limb_t vgtu, t0; |
109 | 0 | int c; |
110 | 0 | sub_ddmmss (vgtu, t0, 0, u0, 0, v0); |
111 | 0 | if (UNLIKELY (t0 == 0)) |
112 | 0 | { |
113 | 0 | g.d1 = u0 >> (GMP_LIMB_BITS - 1); |
114 | 0 | g.d0 = (u0 << 1) | 1; |
115 | 0 | return g; |
116 | 0 | } |
117 | | |
118 | | /* v <-- min (u, v) */ |
119 | 0 | v0 += (vgtu & t0); |
120 | | |
121 | | /* u <-- |u - v| */ |
122 | 0 | u0 = (t0 ^ vgtu) - vgtu; |
123 | |
|
124 | 0 | count_trailing_zeros (c, t0); |
125 | 0 | u0 = (u0 >> 1) >> c; |
126 | 0 | } |
127 | | |
128 | 0 | g.d0 = mpn_gcd_11 ((u0 << 1) + 1, (v0 << 1) + 1); |
129 | 0 | g.d1 = 0; |
130 | 0 | return g; |
131 | 0 | } |