1- use core:: ops;
2-
3- use int:: Int ;
41use int:: LargeInt ;
2+ use int:: { DInt , HInt , Int } ;
53
64trait Mul : LargeInt {
75 fn mul ( self , other : Self ) -> Self {
@@ -29,59 +27,72 @@ trait Mul: LargeInt {
2927impl Mul for u64 { }
3028impl Mul for i128 { }
3129
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 ( ) )
3940 }
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 ( ) )
4546 }
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 ) ,
4749 }
50+ }
51+ }
4852
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 ) ;
6065 }
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( ) ;
6471 }
65- }
66- result
67- }
68- }
72+ if rhs_neg {
73+ rhs = rhs . wrapping_neg ( ) ;
74+ }
75+ let mul_neg = lhs_neg != rhs_neg ;
6976
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;
7379
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+ }
8089 }
81- result
82- }
90+ } ;
8391}
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 ) ;
8596
8697intrinsics ! {
8798 #[ maybe_use_optimized_c_shim]
@@ -95,27 +106,29 @@ intrinsics! {
95106 }
96107
97108 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
99112 }
100113
101114 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
103118 }
104119
105120 #[ unadjusted_on_win64]
106121 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
108125 }
109126
110127 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)
114129 }
115130
116131 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)
120133 }
121134}
0 commit comments