1
- use core:: ops;
2
-
3
- use int:: Int ;
4
1
use int:: LargeInt ;
2
+ use int:: { DInt , HInt , Int } ;
5
3
6
4
trait Mul : LargeInt {
7
5
fn mul ( self , other : Self ) -> Self {
@@ -29,59 +27,72 @@ trait Mul: LargeInt {
29
27
impl Mul for u64 { }
30
28
impl Mul for i128 { }
31
29
32
- trait Mulo : Int + ops:: Neg < Output = Self > {
33
- fn mulo ( self , other : Self , overflow : & mut i32 ) -> Self {
34
- * overflow = 0 ;
35
- let result = self . wrapping_mul ( other) ;
36
- if self == Self :: min_value ( ) {
37
- if other != Self :: ZERO && other != Self :: ONE {
38
- * overflow = 1 ;
30
+ pub ( crate ) trait UMulo : Int + DInt {
31
+ fn mulo ( self , rhs : Self ) -> ( Self , bool ) {
32
+ match ( self . hi ( ) . is_zero ( ) , rhs. hi ( ) . is_zero ( ) ) {
33
+ // overflow is guaranteed
34
+ ( false , false ) => ( self . wrapping_mul ( rhs) , true ) ,
35
+ ( true , false ) => {
36
+ let mul_lo = self . lo ( ) . widen_mul ( rhs. lo ( ) ) ;
37
+ let mul_hi = self . lo ( ) . widen_mul ( rhs. hi ( ) ) ;
38
+ let ( mul, o) = mul_lo. overflowing_add ( mul_hi. lo ( ) . widen_hi ( ) ) ;
39
+ ( mul, o || !mul_hi. hi ( ) . is_zero ( ) )
39
40
}
40
- return result ;
41
- }
42
- if other == Self :: min_value ( ) {
43
- if self != Self :: ZERO && self != Self :: ONE {
44
- * overflow = 1 ;
41
+ ( false , true ) => {
42
+ let mul_lo = rhs . lo ( ) . widen_mul ( self . lo ( ) ) ;
43
+ let mul_hi = rhs . lo ( ) . widen_mul ( self . hi ( ) ) ;
44
+ let ( mul , o ) = mul_lo . overflowing_add ( mul_hi . lo ( ) . widen_hi ( ) ) ;
45
+ ( mul , o || !mul_hi . hi ( ) . is_zero ( ) )
45
46
}
46
- return result;
47
+ // overflow is guaranteed to not happen, and use a smaller widening multiplication
48
+ ( true , true ) => ( self . lo ( ) . widen_mul ( rhs. lo ( ) ) , false ) ,
47
49
}
50
+ }
51
+ }
48
52
49
- let sa = self >> ( Self :: BITS - 1 ) ;
50
- let abs_a = ( self ^ sa) - sa;
51
- let sb = other >> ( Self :: BITS - 1 ) ;
52
- let abs_b = ( other ^ sb) - sb;
53
- let two = Self :: ONE + Self :: ONE ;
54
- if abs_a < two || abs_b < two {
55
- return result;
56
- }
57
- if sa == sb {
58
- if abs_a > Self :: max_value ( ) . aborting_div ( abs_b) {
59
- * overflow = 1 ;
53
+ impl UMulo for u32 { }
54
+ impl UMulo for u64 { }
55
+ impl UMulo for u128 { }
56
+
57
+ macro_rules! impl_signed_mulo {
58
+ ( $fn: ident, $iD: ident, $uD: ident) => {
59
+ fn $fn( lhs: $iD, rhs: $iD) -> ( $iD, bool ) {
60
+ let mut lhs = lhs;
61
+ let mut rhs = rhs;
62
+ // the test against `mul_neg` below fails without this early return
63
+ if lhs == 0 || rhs == 0 {
64
+ return ( 0 , false ) ;
60
65
}
61
- } else {
62
- if abs_a > Self :: min_value ( ) . aborting_div ( -abs_b) {
63
- * overflow = 1 ;
66
+
67
+ let lhs_neg = lhs < 0 ;
68
+ let rhs_neg = rhs < 0 ;
69
+ if lhs_neg {
70
+ lhs = lhs. wrapping_neg( ) ;
64
71
}
65
- }
66
- result
67
- }
68
- }
72
+ if rhs_neg {
73
+ rhs = rhs . wrapping_neg ( ) ;
74
+ }
75
+ let mul_neg = lhs_neg != rhs_neg ;
69
76
70
- impl Mulo for i32 { }
71
- impl Mulo for i64 { }
72
- impl Mulo for i128 { }
77
+ let ( mul, o) = ( lhs as $uD) . mulo( rhs as $uD) ;
78
+ let mut mul = mul as $iD;
73
79
74
- trait UMulo : Int {
75
- fn mulo ( self , other : Self , overflow : & mut i32 ) -> Self {
76
- * overflow = 0 ;
77
- let result = self . wrapping_mul ( other) ;
78
- if self > Self :: max_value ( ) . aborting_div ( other) {
79
- * overflow = 1 ;
80
+ if mul_neg {
81
+ mul = mul. wrapping_neg( ) ;
82
+ }
83
+ if ( mul < 0 ) != mul_neg {
84
+ // this one check happens to catch all edge cases related to `$iD::MIN`
85
+ ( mul, true )
86
+ } else {
87
+ ( mul, o)
88
+ }
80
89
}
81
- result
82
- }
90
+ } ;
83
91
}
84
- impl UMulo for u128 { }
92
+
93
+ impl_signed_mulo ! ( i32_overflowing_mul, i32 , u32 ) ;
94
+ impl_signed_mulo ! ( i64_overflowing_mul, i64 , u64 ) ;
95
+ impl_signed_mulo ! ( i128_overflowing_mul, i128 , u128 ) ;
85
96
86
97
intrinsics ! {
87
98
#[ maybe_use_optimized_c_shim]
@@ -95,27 +106,29 @@ intrinsics! {
95
106
}
96
107
97
108
pub extern "C" fn __mulosi4( a: i32 , b: i32 , oflow: & mut i32 ) -> i32 {
98
- a. mulo( b, oflow)
109
+ let ( mul, o) = i32_overflowing_mul( a, b) ;
110
+ * oflow = o as i32 ;
111
+ mul
99
112
}
100
113
101
114
pub extern "C" fn __mulodi4( a: i64 , b: i64 , oflow: & mut i32 ) -> i64 {
102
- a. mulo( b, oflow)
115
+ let ( mul, o) = i64_overflowing_mul( a, b) ;
116
+ * oflow = o as i32 ;
117
+ mul
103
118
}
104
119
105
120
#[ unadjusted_on_win64]
106
121
pub extern "C" fn __muloti4( a: i128 , b: i128 , oflow: & mut i32 ) -> i128 {
107
- a. mulo( b, oflow)
122
+ let ( mul, o) = i128_overflowing_mul( a, b) ;
123
+ * oflow = o as i32 ;
124
+ mul
108
125
}
109
126
110
127
pub extern "C" fn __rust_i128_mulo( a: i128 , b: i128 ) -> ( i128 , bool ) {
111
- let mut oflow = 0 ;
112
- let r = __muloti4( a, b, & mut oflow) ;
113
- ( r, oflow != 0 )
128
+ i128_overflowing_mul( a, b)
114
129
}
115
130
116
131
pub extern "C" fn __rust_u128_mulo( a: u128 , b: u128 ) -> ( u128 , bool ) {
117
- let mut oflow = 0 ;
118
- let r = a. mulo( b, & mut oflow) ;
119
- ( r, oflow != 0 )
132
+ a. mulo( b)
120
133
}
121
134
}
0 commit comments