@@ -10,12 +10,15 @@ use core::ops::{Div, DivAssign, Rem, RemAssign};
10
10
use num_integer:: Integer ;
11
11
use num_traits:: { CheckedDiv , CheckedEuclid , Euclid , One , ToPrimitive , Zero } ;
12
12
13
+ pub ( super ) const FAST_DIV_WIDE : bool = cfg ! ( any( target_arch = "x86" , target_arch = "x86_64" ) ) ;
14
+
13
15
/// Divide a two digit numerator by a one digit divisor, returns quotient and remainder:
14
16
///
15
17
/// Note: the caller must ensure that both the quotient and remainder will fit into a single digit.
16
18
/// This is _not_ true for an arbitrary numerator/denominator.
17
19
///
18
20
/// (This function also matches what the x86 divide instruction does).
21
+ #[ cfg( any( miri, not( any( target_arch = "x86" , target_arch = "x86_64" ) ) ) ) ]
19
22
#[ inline]
20
23
fn div_wide ( hi : BigDigit , lo : BigDigit , divisor : BigDigit ) -> ( BigDigit , BigDigit ) {
21
24
debug_assert ! ( hi < divisor) ;
@@ -25,6 +28,34 @@ fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigi
25
28
( ( lhs / rhs) as BigDigit , ( lhs % rhs) as BigDigit )
26
29
}
27
30
31
+ /// x86 and x86_64 can use a real `div` instruction.
32
+ #[ cfg( all( not( miri) , any( target_arch = "x86" , target_arch = "x86_64" ) ) ) ]
33
+ #[ inline]
34
+ fn div_wide ( hi : BigDigit , lo : BigDigit , divisor : BigDigit ) -> ( BigDigit , BigDigit ) {
35
+ // This debug assertion covers the potential #DE for divisor==0 or a quotient too large for one
36
+ // register, otherwise in release mode it will become a target-specific fault like SIGFPE.
37
+ // This should never occur with the inputs from our few `div_wide` callers.
38
+ debug_assert ! ( hi < divisor) ;
39
+
40
+ // SAFETY: The `div` instruction only affects registers, reading the explicit operand as the
41
+ // divisor, and implicitly reading RDX:RAX or EDX:EAX as the dividend. The result is implicitly
42
+ // written back to RAX or EAX for the quotient and RDX or EDX for the remainder. No memory is
43
+ // used, and flags are not preserved.
44
+ unsafe {
45
+ let ( div, rem) ;
46
+
47
+ core:: arch:: asm!(
48
+ "div {}" ,
49
+ in( reg) divisor,
50
+ inout( "dx" ) hi => rem,
51
+ inout( "ax" ) lo => div,
52
+ options( pure, nomem, nostack) ,
53
+ ) ;
54
+
55
+ ( div, rem)
56
+ }
57
+ }
58
+
28
59
/// For small divisors, we can divide without promoting to `DoubleBigDigit` by
29
60
/// using half-size pieces of digit, like long-division.
30
61
#[ inline]
@@ -45,7 +76,7 @@ pub(super) fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit)
45
76
46
77
let mut rem = 0 ;
47
78
48
- if b <= big_digit:: HALF {
79
+ if ! FAST_DIV_WIDE && b <= big_digit:: HALF {
49
80
for d in a. data . iter_mut ( ) . rev ( ) {
50
81
let ( q, r) = div_half ( rem, * d, b) ;
51
82
* d = q;
@@ -70,7 +101,7 @@ fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
70
101
71
102
let mut rem = 0 ;
72
103
73
- if b <= big_digit:: HALF {
104
+ if ! FAST_DIV_WIDE && b <= big_digit:: HALF {
74
105
for & digit in a. data . iter ( ) . rev ( ) {
75
106
let ( _, r) = div_half ( rem, digit, b) ;
76
107
rem = r;
@@ -230,7 +261,7 @@ fn div_rem_core(mut a: BigUint, b: &[BigDigit]) -> (BigUint, BigUint) {
230
261
let mut a0 = 0 ;
231
262
232
263
// [b1, b0] are the two most significant digits of the divisor. They never change.
233
- let b0 = * b . last ( ) . unwrap ( ) ;
264
+ let b0 = b [ b . len ( ) - 1 ] ;
234
265
let b1 = b[ b. len ( ) - 2 ] ;
235
266
236
267
let q_len = a. data . len ( ) - b. len ( ) + 1 ;
0 commit comments