@@ -12,30 +12,42 @@ use crate::bigint::BigInt;
12
12
use crate :: bigint:: Sign ;
13
13
use crate :: bigint:: Sign :: { Minus , NoSign , Plus } ;
14
14
15
- use crate :: big_digit:: { self , BigDigit , DoubleBigDigit , SignedDoubleBigDigit } ;
15
+ use crate :: big_digit:: { self , BigDigit , DoubleBigDigit } ;
16
+
17
+ #[ cfg( not( use_addcarry_u64) ) ] // only needed for the fallback implementation of `sbb`
18
+ use crate :: big_digit:: SignedDoubleBigDigit ;
16
19
17
20
// Generic functions for add/subtract/multiply with carry/borrow:
18
21
19
22
// Add with carry:
20
- #[ allow ( unused ) ]
23
+ #[ cfg ( use_addcarry_u64 ) ]
21
24
#[ inline]
22
- fn adc ( a : BigDigit , b : BigDigit , acc : & mut DoubleBigDigit ) -> BigDigit {
23
- * acc += DoubleBigDigit :: from ( a) ;
24
- * acc += DoubleBigDigit :: from ( b) ;
25
- let lo = * acc as BigDigit ;
26
- * acc >>= big_digit:: BITS ;
27
- lo
25
+ fn adc ( carry : u8 , a : BigDigit , b : BigDigit , out : & mut BigDigit ) -> u8 {
26
+ unsafe { core:: arch:: x86_64:: _addcarry_u64 ( carry, a, b, out) }
27
+ }
28
+
29
+ #[ cfg( not( use_addcarry_u64) ) ] // fallback for environments where we don't have an addcarry intrinsic
30
+ #[ inline]
31
+ fn adc ( mut carry : DoubleBigDigit , a : BigDigit , b : BigDigit , out : & mut BigDigit ) -> DoubleBigDigit {
32
+ carry += DoubleBigDigit :: from ( a) ;
33
+ carry += DoubleBigDigit :: from ( b) ;
34
+ * out = carry as BigDigit ;
35
+ carry >> big_digit:: BITS
28
36
}
29
37
30
38
// Subtract with borrow:
31
- #[ allow ( unused ) ]
39
+ #[ cfg ( use_addcarry_u64 ) ]
32
40
#[ inline]
33
- fn sbb ( a : BigDigit , b : BigDigit , acc : & mut SignedDoubleBigDigit ) -> BigDigit {
34
- * acc += SignedDoubleBigDigit :: from ( a) ;
35
- * acc -= SignedDoubleBigDigit :: from ( b) ;
36
- let lo = * acc as BigDigit ;
37
- * acc >>= big_digit:: BITS ;
38
- lo
41
+ fn sbb ( carry : u8 , a : BigDigit , b : BigDigit , out : & mut BigDigit ) -> u8 {
42
+ unsafe { core:: arch:: x86_64:: _subborrow_u64 ( carry, a, b, out) }
43
+ }
44
+ #[ cfg( not( use_addcarry_u64) ) ] // fallback for environments where we don't have an addcarry intrinsic
45
+ #[ inline]
46
+ fn sbb ( mut carry : SignedDoubleBigDigit , a : BigDigit , b : BigDigit , out : & mut BigDigit ) -> SignedDoubleBigDigit {
47
+ carry += SignedDoubleBigDigit :: from ( a) ;
48
+ carry -= SignedDoubleBigDigit :: from ( b) ;
49
+ * out = carry as BigDigit ;
50
+ carry >> big_digit:: BITS
39
51
}
40
52
41
53
#[ inline]
@@ -134,41 +146,6 @@ pub(crate) fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
134
146
/// the addition first hoping that it will fit.
135
147
///
136
148
/// The caller _must_ ensure that `a` is at least as long as `b`.
137
- #[ cfg( all( u64_digit, target_arch = "x86_64" ) ) ] // only run on x86_64, when we have u64 digits
138
- #[ inline]
139
- pub ( crate ) fn __add2 ( a : & mut [ BigDigit ] , b : & [ BigDigit ] ) -> BigDigit {
140
- debug_assert ! ( a. len( ) >= b. len( ) ) ;
141
-
142
- use core:: arch:: x86_64:: _addcarry_u64;
143
-
144
- let mut carry = 0 ;
145
- let ( a_lo, a_hi) = a. split_at_mut ( b. len ( ) ) ;
146
-
147
- for ( a, b) in a_lo. iter_mut ( ) . zip ( b) {
148
- // Safety: There are absolutely no safety concerns with calling _addcarry_u64, it's just unsafe for API consistency with other intrinsics
149
- carry = unsafe { _addcarry_u64 ( carry, * a, * b, a) } ;
150
- }
151
-
152
- if carry != 0 {
153
- for a in a_hi {
154
- // Safety: There are absolutely no safety concerns with calling _addcarry_u64, it's just unsafe for API consistency with other intrinsics
155
- carry = unsafe { _addcarry_u64 ( carry, * a, 0 , a) } ;
156
- if carry == 0 {
157
- break ;
158
- }
159
- }
160
- }
161
-
162
- carry as BigDigit
163
- }
164
-
165
- /// Two argument addition of raw slices, `a += b`, returning the carry.
166
- ///
167
- /// This is used when the data `Vec` might need to resize to push a non-zero carry, so we perform
168
- /// the addition first hoping that it will fit.
169
- ///
170
- /// The caller _must_ ensure that `a` is at least as long as `b`.
171
- #[ cfg( not( all( u64_digit, target_arch = "x86_64" ) ) ) ] // run if we aren't using 64-bit digits, or if we're not running on x86_64
172
149
#[ inline]
173
150
pub ( crate ) fn __add2 ( a : & mut [ BigDigit ] , b : & [ BigDigit ] ) -> BigDigit {
174
151
debug_assert ! ( a. len( ) >= b. len( ) ) ;
@@ -177,12 +154,12 @@ pub(crate) fn __add2(a: &mut [BigDigit], b: &[BigDigit]) -> BigDigit {
177
154
let ( a_lo, a_hi) = a. split_at_mut ( b. len ( ) ) ;
178
155
179
156
for ( a, b) in a_lo. iter_mut ( ) . zip ( b) {
180
- * a = adc ( * a, * b, & mut carry ) ;
157
+ carry = adc ( carry , * a, * b, a ) ;
181
158
}
182
159
183
160
if carry != 0 {
184
161
for a in a_hi {
185
- * a = adc ( * a, 0 , & mut carry ) ;
162
+ carry = adc ( carry , * a, 0 , a ) ;
186
163
if carry == 0 {
187
164
break ;
188
165
}
@@ -203,39 +180,6 @@ pub(crate) fn add2(a: &mut [BigDigit], b: &[BigDigit]) {
203
180
debug_assert ! ( carry == 0 ) ;
204
181
}
205
182
206
- #[ cfg( all( u64_digit, target_arch = "x86_64" ) ) ] // only run on x86_64, when we have u64 digits
207
- pub ( crate ) fn sub2 ( a : & mut [ BigDigit ] , b : & [ BigDigit ] ) {
208
- use core:: arch:: x86_64:: _subborrow_u64;
209
-
210
- let mut borrow = 0 ;
211
-
212
- let len = cmp:: min ( a. len ( ) , b. len ( ) ) ;
213
- let ( a_lo, a_hi) = a. split_at_mut ( len) ;
214
- let ( b_lo, b_hi) = b. split_at ( len) ;
215
-
216
- for ( a, b) in a_lo. iter_mut ( ) . zip ( b_lo) {
217
- // Safety: There are absolutely no safety concerns with calling _subborrow_u64, it's just unsafe for API consistency with other intrinsics
218
- borrow = unsafe { _subborrow_u64 ( borrow, * a, * b, a) } ;
219
- }
220
-
221
- if borrow != 0 {
222
- for a in a_hi {
223
- // Safety: There are absolutely no safety concerns with calling _subborrow_u64, it's just unsafe for API consistency with other intrinsics
224
- borrow = unsafe { _subborrow_u64 ( borrow, * a, 0 , a) } ;
225
- if borrow == 0 {
226
- break ;
227
- }
228
- }
229
- }
230
-
231
- // note: we're _required_ to fail on underflow
232
- assert ! (
233
- borrow == 0 && b_hi. iter( ) . all( |x| * x == 0 ) ,
234
- "Cannot subtract b from a because b is larger than a."
235
- ) ;
236
- }
237
-
238
- #[ cfg( not( all( u64_digit, target_arch = "x86_64" ) ) ) ] // run if we aren't using 64-bit digits, or if we're not running on x86_64
239
183
pub ( crate ) fn sub2 ( a : & mut [ BigDigit ] , b : & [ BigDigit ] ) {
240
184
let mut borrow = 0 ;
241
185
@@ -244,12 +188,12 @@ pub(crate) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
244
188
let ( b_lo, b_hi) = b. split_at ( len) ;
245
189
246
190
for ( a, b) in a_lo. iter_mut ( ) . zip ( b_lo) {
247
- * a = sbb ( * a, * b, & mut borrow ) ;
191
+ borrow = sbb ( borrow , * a, * b, a ) ;
248
192
}
249
193
250
194
if borrow != 0 {
251
195
for a in a_hi {
252
- * a = sbb ( * a, 0 , & mut borrow ) ;
196
+ borrow = sbb ( borrow , * a, 0 , a ) ;
253
197
if borrow == 0 {
254
198
break ;
255
199
}
@@ -264,32 +208,14 @@ pub(crate) fn sub2(a: &mut [BigDigit], b: &[BigDigit]) {
264
208
}
265
209
266
210
// Only for the Sub impl. `a` and `b` must have same length.
267
- #[ cfg( all( u64_digit, target_arch = "x86_64" ) ) ] // only run on x86_64, when we have u64 digits
268
- #[ inline]
269
- pub ( crate ) fn __sub2rev ( a : & [ BigDigit ] , b : & mut [ BigDigit ] ) -> BigDigit {
270
- use core:: arch:: x86_64:: _subborrow_u64;
271
- debug_assert ! ( b. len( ) == a. len( ) ) ;
272
-
273
- let mut borrow = 0 ;
274
-
275
- for ( ai, bi) in a. iter ( ) . zip ( b) {
276
- // Safety: There are absolutely no safety concerns with calling _subborrow_u64, it's just unsafe for API consistency with other intrinsics
277
- borrow = unsafe { _subborrow_u64 ( borrow, * ai, * bi, bi) } ;
278
- }
279
-
280
- borrow as BigDigit
281
- }
282
-
283
- // Only for the Sub impl. `a` and `b` must have same length.
284
- #[ cfg( not( all( u64_digit, target_arch = "x86_64" ) ) ) ] // run if we aren't using 64-bit digits, or if we're not running on x86_64
285
211
#[ inline]
286
212
pub ( crate ) fn __sub2rev ( a : & [ BigDigit ] , b : & mut [ BigDigit ] ) -> BigDigit {
287
213
debug_assert ! ( b. len( ) == a. len( ) ) ;
288
214
289
215
let mut borrow = 0 ;
290
216
291
217
for ( ai, bi) in a. iter ( ) . zip ( b) {
292
- * bi = sbb ( * ai, * bi, & mut borrow ) ;
218
+ borrow = sbb ( borrow , * ai, * bi, bi ) ;
293
219
}
294
220
295
221
borrow as BigDigit
0 commit comments