@@ -18,6 +18,7 @@ use num_traits::{CheckedDiv, One, ToPrimitive, Zero};
18
18
/// This is _not_ true for an arbitrary numerator/denominator.
19
19
///
20
20
/// (This function also matches what the x86 divide instruction does).
21
+ #[ cfg( not( use_x86_div) ) ]
21
22
#[ inline]
22
23
fn div_wide ( hi : BigDigit , lo : BigDigit , divisor : BigDigit ) -> ( BigDigit , BigDigit ) {
23
24
debug_assert ! ( hi < divisor) ;
@@ -27,6 +28,44 @@ fn div_wide(hi: BigDigit, lo: BigDigit, divisor: BigDigit) -> (BigDigit, BigDigi
27
28
( ( lhs / rhs) as BigDigit , ( lhs % rhs) as BigDigit )
28
29
}
29
30
31
+ /// With Rust 1.59+ for stable `asm!`, x86 and x86_64 can use a real `div` instruction.
32
+ #[ cfg( use_x86_div) ]
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
+ #[ cfg( u64_digit) ]
48
+ core:: arch:: asm!(
49
+ "div {:r}" ,
50
+ in( reg) divisor,
51
+ inout( "rdx" ) hi => rem,
52
+ inout( "rax" ) lo => div,
53
+ options( pure, nomem, nostack) ,
54
+ ) ;
55
+
56
+ #[ cfg( not( u64_digit) ) ]
57
+ core:: arch:: asm!(
58
+ "div {:e}" ,
59
+ in( reg) divisor,
60
+ inout( "edx" ) hi => rem,
61
+ inout( "eax" ) lo => div,
62
+ options( pure, nomem, nostack) ,
63
+ ) ;
64
+
65
+ ( div, rem)
66
+ }
67
+ }
68
+
30
69
/// For small divisors, we can divide without promoting to `DoubleBigDigit` by
31
70
/// using half-size pieces of digit, like long-division.
32
71
#[ inline]
@@ -47,7 +86,7 @@ pub(super) fn div_rem_digit(mut a: BigUint, b: BigDigit) -> (BigUint, BigDigit)
47
86
48
87
let mut rem = 0 ;
49
88
50
- if b <= big_digit:: HALF {
89
+ if ! cfg ! ( use_x86_div ) && b <= big_digit:: HALF {
51
90
for d in a. data . iter_mut ( ) . rev ( ) {
52
91
let ( q, r) = div_half ( rem, * d, b) ;
53
92
* d = q;
@@ -72,7 +111,7 @@ fn rem_digit(a: &BigUint, b: BigDigit) -> BigDigit {
72
111
73
112
let mut rem = 0 ;
74
113
75
- if b <= big_digit:: HALF {
114
+ if ! cfg ! ( use_x86_div ) && b <= big_digit:: HALF {
76
115
for & digit in a. data . iter ( ) . rev ( ) {
77
116
let ( _, r) = div_half ( rem, digit, b) ;
78
117
rem = r;
@@ -232,7 +271,7 @@ fn div_rem_core(mut a: BigUint, b: &[BigDigit]) -> (BigUint, BigUint) {
232
271
let mut a0 = 0 ;
233
272
234
273
// [b1, b0] are the two most significant digits of the divisor. They never change.
235
- let b0 = * b . last ( ) . unwrap ( ) ;
274
+ let b0 = b [ b . len ( ) - 1 ] ;
236
275
let b1 = b[ b. len ( ) - 2 ] ;
237
276
238
277
let q_len = a. data . len ( ) - b. len ( ) + 1 ;
0 commit comments