@@ -901,26 +901,46 @@ macro_rules! int_impl {
901901 #[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
902902 #[ must_use = "this returns the result of the operation, \
903903 without modifying the original"]
904+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
904905 #[ inline]
905906 pub const fn checked_pow( self , mut exp: u32 ) -> Option <Self > {
906- if exp == 0 {
907- return Some ( 1 ) ;
908- }
909- let mut base = self ;
910- let mut acc: Self = 1 ;
907+ // SAFETY: This path has the same behavior as the other.
908+ if unsafe { intrinsics:: is_val_statically_known( self ) }
909+ && self . unsigned_abs( ) . is_power_of_two( )
910+ {
911+ // SAFETY: We just checked this is a power of two. and above zero.
912+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
913+ let num_shl = power_used. saturating_mul( exp) ;
914+ let res = try_opt!( ( 1 as Self ) . checked_shl( num_shl) ) ;
915+
916+ let sign = self . is_negative( ) && exp & 1 != 0 ;
917+ if !sign && res == Self :: MIN {
918+ None
919+ } else if sign {
920+ Some ( res. wrapping_neg( ) )
921+ } else {
922+ Some ( res)
923+ }
924+ } else {
925+ if exp == 0 {
926+ return Some ( 1 ) ;
927+ }
928+ let mut base = self ;
929+ let mut acc: Self = 1 ;
911930
912- while exp > 1 {
913- if ( exp & 1 ) == 1 {
914- acc = try_opt!( acc. checked_mul( base) ) ;
931+ while exp > 1 {
932+ if ( exp & 1 ) == 1 {
933+ acc = try_opt!( acc. checked_mul( base) ) ;
934+ }
935+ exp /= 2 ;
936+ base = try_opt!( base. checked_mul( base) ) ;
915937 }
916- exp /= 2 ;
917- base = try_opt!( base. checked_mul( base) ) ;
938+ // since exp!=0, finally the exp must be 1.
939+ // Deal with the final bit of the exponent separately, since
940+ // squaring the base afterwards is not necessary and may cause a
941+ // needless overflow.
942+ acc. checked_mul( base)
918943 }
919- // since exp!=0, finally the exp must be 1.
920- // Deal with the final bit of the exponent separately, since
921- // squaring the base afterwards is not necessary and may cause a
922- // needless overflow.
923- acc. checked_mul( base)
924944 }
925945
926946 /// Returns the square root of the number, rounded down.
@@ -1537,27 +1557,48 @@ macro_rules! int_impl {
15371557 #[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
15381558 #[ must_use = "this returns the result of the operation, \
15391559 without modifying the original"]
1560+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
15401561 #[ inline]
15411562 pub const fn wrapping_pow( self , mut exp: u32 ) -> Self {
1542- if exp == 0 {
1543- return 1 ;
1544- }
1545- let mut base = self ;
1546- let mut acc: Self = 1 ;
1563+ // SAFETY: This path has the same behavior as the other.
1564+ if unsafe { intrinsics:: is_val_statically_known( self ) }
1565+ && self . unsigned_abs( ) . is_power_of_two( )
1566+ {
1567+ // SAFETY: We just checked this is a power of two. and above zero.
1568+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
1569+ let num_shl = power_used. saturating_mul( exp) ;
1570+ let res = match ( 1 as Self ) . checked_shl( num_shl) {
1571+ Some ( x) => x,
1572+ None => 0
1573+ } ;
15471574
1548- while exp > 1 {
1549- if ( exp & 1 ) == 1 {
1550- acc = acc. wrapping_mul( base) ;
1575+ let sign = self . is_negative( ) && exp & 1 != 0 ;
1576+ if sign {
1577+ res. wrapping_neg( )
1578+ } else {
1579+ res
15511580 }
1552- exp /= 2 ;
1553- base = base. wrapping_mul( base) ;
1554- }
1581+ } else {
1582+ if exp == 0 {
1583+ return 1 ;
1584+ }
1585+ let mut base = self ;
1586+ let mut acc: Self = 1 ;
15551587
1556- // since exp!=0, finally the exp must be 1.
1557- // Deal with the final bit of the exponent separately, since
1558- // squaring the base afterwards is not necessary and may cause a
1559- // needless overflow.
1560- acc. wrapping_mul( base)
1588+ while exp > 1 {
1589+ if ( exp & 1 ) == 1 {
1590+ acc = acc. wrapping_mul( base) ;
1591+ }
1592+ exp /= 2 ;
1593+ base = base. wrapping_mul( base) ;
1594+ }
1595+
1596+ // since exp!=0, finally the exp must be 1.
1597+ // Deal with the final bit of the exponent separately, since
1598+ // squaring the base afterwards is not necessary and may cause a
1599+ // needless overflow.
1600+ acc. wrapping_mul( base)
1601+ }
15611602 }
15621603
15631604 /// Calculates `self` + `rhs`
@@ -2039,36 +2080,58 @@ macro_rules! int_impl {
20392080 #[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
20402081 #[ must_use = "this returns the result of the operation, \
20412082 without modifying the original"]
2083+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
20422084 #[ inline]
20432085 pub const fn overflowing_pow( self , mut exp: u32 ) -> ( Self , bool ) {
2044- if exp == 0 {
2045- return ( 1 , false ) ;
2046- }
2047- let mut base = self ;
2048- let mut acc: Self = 1 ;
2049- let mut overflown = false ;
2050- // Scratch space for storing results of overflowing_mul.
2051- let mut r;
2052-
2053- while exp > 1 {
2054- if ( exp & 1 ) == 1 {
2055- r = acc. overflowing_mul( base) ;
2056- acc = r. 0 ;
2086+ // SAFETY: This path has the same behavior as the other.
2087+ if unsafe { intrinsics:: is_val_statically_known( self ) }
2088+ && self . unsigned_abs( ) . is_power_of_two( )
2089+ {
2090+ // SAFETY: We just checked this is a power of two. and above zero.
2091+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs( ) ) as u32 } ;
2092+ let num_shl = power_used. saturating_mul( exp) ;
2093+ let res = match ( 1 as Self ) . checked_shl( num_shl) {
2094+ Some ( x) => x,
2095+ None => 0
2096+ } ;
2097+
2098+ let sign = self . is_negative( ) && exp & 1 != 0 ;
2099+ let overflow = res == 0 || ( sign && res == Self :: MIN ) ;
2100+ if sign {
2101+ ( res. wrapping_neg( ) , overflow)
2102+ } else {
2103+ ( res, overflow)
2104+ }
2105+ } else {
2106+ if exp == 0 {
2107+ return ( 1 , false ) ;
2108+ }
2109+ let mut base = self ;
2110+ let mut acc: Self = 1 ;
2111+ let mut overflown = false ;
2112+ // Scratch space for storing results of overflowing_mul.
2113+ let mut r;
2114+
2115+ while exp > 1 {
2116+ if ( exp & 1 ) == 1 {
2117+ r = acc. overflowing_mul( base) ;
2118+ acc = r. 0 ;
2119+ overflown |= r. 1 ;
2120+ }
2121+ exp /= 2 ;
2122+ r = base. overflowing_mul( base) ;
2123+ base = r. 0 ;
20572124 overflown |= r. 1 ;
20582125 }
2059- exp /= 2 ;
2060- r = base. overflowing_mul( base) ;
2061- base = r. 0 ;
2062- overflown |= r. 1 ;
2063- }
20642126
2065- // since exp!=0, finally the exp must be 1.
2066- // Deal with the final bit of the exponent separately, since
2067- // squaring the base afterwards is not necessary and may cause a
2068- // needless overflow.
2069- r = acc. overflowing_mul( base) ;
2070- r. 1 |= overflown;
2071- r
2127+ // since exp!=0, finally the exp must be 1.
2128+ // Deal with the final bit of the exponent separately, since
2129+ // squaring the base afterwards is not necessary and may cause a
2130+ // needless overflow.
2131+ r = acc. overflowing_mul( base) ;
2132+ r. 1 |= overflown;
2133+ r
2134+ }
20722135 }
20732136
20742137 /// Raises self to the power of `exp`, using exponentiation by squaring.
@@ -2086,30 +2149,34 @@ macro_rules! int_impl {
20862149 #[ rustc_const_stable( feature = "const_int_pow" , since = "1.50.0" ) ]
20872150 #[ must_use = "this returns the result of the operation, \
20882151 without modifying the original"]
2152+ #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
20892153 #[ inline]
20902154 #[ rustc_inherit_overflow_checks]
20912155 #[ track_caller] // Hides the hackish overflow check for powers of two.
2092- #[ rustc_allow_const_fn_unstable( is_val_statically_known) ]
20932156 pub const fn pow( self , mut exp: u32 ) -> Self {
20942157 // SAFETY: This path has the same behavior as the other.
20952158 if unsafe { intrinsics:: is_val_statically_known( self ) }
2096- && self > 0
2097- && ( self & ( self - 1 ) == 0 )
2159+ && self . unsigned_abs( ) . is_power_of_two( )
20982160 {
20992161 // SAFETY: We just checked this is a power of two. and above zero.
2100- let power_used = unsafe { intrinsics:: cttz_nonzero( self ) as u32 } ;
2162+ let power_used = unsafe { intrinsics:: cttz_nonzero( self . wrapping_abs ( ) ) as u32 } ;
21012163 let num_shl = power_used. saturating_mul( exp) ;
21022164 let res = match ( 1 as Self ) . checked_shl( num_shl) {
21032165 Some ( x) => x,
21042166 None => 0
21052167 } ;
21062168
2169+ let sign = self . is_negative( ) && exp & 1 != 0 ;
21072170 #[ allow( arithmetic_overflow) ]
2108- if res <= 0 {
2171+ if res == 0 || ( !sign && res == Self :: MIN ) {
21092172 // So it panics.
21102173 _ = Self :: MAX * Self :: MAX ;
21112174 }
2112- res
2175+ if sign {
2176+ res. wrapping_neg( )
2177+ } else {
2178+ res
2179+ }
21132180 } else {
21142181 if exp == 0 {
21152182 return 1 ;
0 commit comments