Skip to content

Commit

Permalink
Rollup merge of rust-lang#40521 - TimNN:panic-free-shift, r=alexcrichton
Browse files Browse the repository at this point in the history
Implemente overflowing_sh* with new unchecked_sh* intrinsics

Also update some 128 bit builtins to not rely on the constant evaluator to avoid checked operations.

Fixes rust-lang#40508.

cc @nagisa, @alexcrichton

Note: I still have a build running to see if the 128 bit changes worked (unoptimized builds take *forever* to compile), however at least the overflowing builtins no longer reference `core::panicking::panic`.
  • Loading branch information
Ariel Ben-Yehuda authored Mar 19, 2017
2 parents 65e697b + e16d286 commit e3cd41a
Show file tree
Hide file tree
Showing 5 changed files with 127 additions and 28 deletions.
18 changes: 9 additions & 9 deletions src/libcompiler_builtins/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ pub mod reimpls {
macro_rules! ashl {
($a:expr, $b:expr, $ty:ty) => {{
let (a, b) = ($a, $b);
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
let half_bits = bits >> 1;
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
let half_bits = bits.wrapping_shr(1);
if b & half_bits != 0 {
<$ty>::from_parts(0, a.low().wrapping_shl(
b.wrapping_sub(half_bits) as u32))
Expand All @@ -58,8 +58,8 @@ pub mod reimpls {
macro_rules! ashr {
($a: expr, $b: expr, $ty:ty) => {{
let (a, b) = ($a, $b);
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
let half_bits = bits >> 1;
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
let half_bits = bits.wrapping_shr(1);
if b & half_bits != 0 {
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32)
as <$ty as LargeInt>::LowHalf,
Expand All @@ -83,8 +83,8 @@ pub mod reimpls {
macro_rules! lshr {
($a: expr, $b: expr, $ty:ty) => {{
let (a, b) = ($a, $b);
let bits = (::core::mem::size_of::<$ty>() * 8) as $ty;
let half_bits = bits >> 1;
let bits = ::core::mem::size_of::<$ty>().wrapping_mul(8) as $ty;
let half_bits = bits.wrapping_shr(1);
if b & half_bits != 0 {
<$ty>::from_parts(a.high().wrapping_shr(b.wrapping_sub(half_bits) as u32), 0)
} else if b == 0 {
Expand Down Expand Up @@ -370,7 +370,7 @@ pub mod reimpls {
macro_rules! mul {
($a:expr, $b:expr, $ty: ty, $tyh: ty) => {{
let (a, b) = ($a, $b);
let half_bits = ((::core::mem::size_of::<$tyh>() * 8) / 2) as u32;
let half_bits = ::core::mem::size_of::<$tyh>().wrapping_mul(4) as u32;
let lower_mask = (!0u64).wrapping_shr(half_bits);
let mut low = (a.low() & lower_mask).wrapping_mul(b.low() & lower_mask);
let mut t = low.wrapping_shr(half_bits);
Expand Down Expand Up @@ -478,7 +478,7 @@ pub mod reimpls {
let mantissa_fraction = repr & <$fromty as FloatStuff>::MANTISSA_MASK;
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;
if sign == -1.0 || exponent < 0 { return 0 as u128; }
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
return !(0 as u128);
}
(if exponent < (<$fromty as FloatStuff>::MANTISSA_BITS) as i32 {
Expand All @@ -503,7 +503,7 @@ pub mod reimpls {
let mantissa = mantissa_fraction | <$fromty as FloatStuff>::MANTISSA_LEAD_BIT;

if exponent < 0 { return 0 as i128; }
if exponent > ::core::mem::size_of::<$outty>() as i32 * 8 {
if exponent > ::core::mem::size_of::<$outty>().wrapping_mul(8) as i32 {
let ret = if sign > 0.0 { <$outty>::max_value() } else { <$outty>::min_value() };
return ret
}
Expand Down
9 changes: 9 additions & 0 deletions src/libcore/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1238,6 +1238,15 @@ extern "rust-intrinsic" {
/// undefined behavior where y = 0 or x = `T::min_value()` and y = -1
pub fn unchecked_rem<T>(x: T, y: T) -> T;

/// Performs an unchecked left shift, resulting in undefined behavior when
/// y < 0 or y >= N, where N is the width of T in bits.
#[cfg(not(stage0))]
pub fn unchecked_shl<T>(x: T, y: T) -> T;
/// Performs an unchecked right shift, resulting in undefined behavior when
/// y < 0 or y >= N, where N is the width of T in bits.
#[cfg(not(stage0))]
pub fn unchecked_shr<T>(x: T, y: T) -> T;

/// Returns (a + b) mod 2^N, where N is the width of T in bits.
/// The stabilized versions of this intrinsic are available on the integer
/// primitives via the `wrapping_add` method. For example,
Expand Down
117 changes: 99 additions & 18 deletions src/libcore/num/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -177,7 +177,7 @@ macro_rules! checked_op {

// `Int` + `SignedInt` implemented for signed integers
macro_rules! int_impl {
($ActualT:ident, $UnsignedT:ty, $BITS:expr,
($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr,
$add_with_overflow:path,
$sub_with_overflow:path,
$mul_with_overflow:path) => {
Expand Down Expand Up @@ -850,6 +850,17 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(not(stage0))]
pub fn wrapping_shl(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
}
}

/// Stage 0
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(stage0)]
pub fn wrapping_shl(self, rhs: u32) -> Self {
self.overflowing_shl(rhs).0
}
Expand All @@ -875,6 +886,17 @@ macro_rules! int_impl {
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(not(stage0))]
pub fn wrapping_shr(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
}
}

/// Stage 0
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(stage0)]
pub fn wrapping_shr(self, rhs: u32) -> Self {
self.overflowing_shr(rhs).0
}
Expand Down Expand Up @@ -1089,6 +1111,15 @@ macro_rules! int_impl {
/// ```
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(not(stage0))]
pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
}

/// Stage 0
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(stage0)]
pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
}
Expand All @@ -1111,6 +1142,15 @@ macro_rules! int_impl {
/// ```
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(not(stage0))]
pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shr(rhs), (rhs > ($BITS - 1)))
}

/// Stage 0
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(stage0)]
pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
}
Expand Down Expand Up @@ -1268,39 +1308,39 @@ macro_rules! int_impl {

#[lang = "i8"]
impl i8 {
int_impl! { i8, u8, 8,
int_impl! { i8, i8, u8, 8,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
}

#[lang = "i16"]
impl i16 {
int_impl! { i16, u16, 16,
int_impl! { i16, i16, u16, 16,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
}

#[lang = "i32"]
impl i32 {
int_impl! { i32, u32, 32,
int_impl! { i32, i32, u32, 32,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
}

#[lang = "i64"]
impl i64 {
int_impl! { i64, u64, 64,
int_impl! { i64, i64, u64, 64,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
}

#[lang = "i128"]
impl i128 {
int_impl! { i128, u128, 128,
int_impl! { i128, i128, u128, 128,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
Expand All @@ -1309,7 +1349,7 @@ impl i128 {
#[cfg(target_pointer_width = "16")]
#[lang = "isize"]
impl isize {
int_impl! { i16, u16, 16,
int_impl! { isize, i16, u16, 16,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
Expand All @@ -1318,7 +1358,7 @@ impl isize {
#[cfg(target_pointer_width = "32")]
#[lang = "isize"]
impl isize {
int_impl! { i32, u32, 32,
int_impl! { isize, i32, u32, 32,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
Expand All @@ -1327,15 +1367,15 @@ impl isize {
#[cfg(target_pointer_width = "64")]
#[lang = "isize"]
impl isize {
int_impl! { i64, u64, 64,
int_impl! { isize, i64, u64, 64,
intrinsics::add_with_overflow,
intrinsics::sub_with_overflow,
intrinsics::mul_with_overflow }
}

// `Int` + `UnsignedInt` implemented for unsigned integers
macro_rules! uint_impl {
($ActualT:ty, $BITS:expr,
($SelfT:ty, $ActualT:ty, $BITS:expr,
$ctpop:path,
$ctlz:path,
$cttz:path,
Expand Down Expand Up @@ -1978,6 +2018,17 @@ macro_rules! uint_impl {
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(not(stage0))]
pub fn wrapping_shl(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT)
}
}

/// Stage 0
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(stage0)]
pub fn wrapping_shl(self, rhs: u32) -> Self {
self.overflowing_shl(rhs).0
}
Expand All @@ -2003,6 +2054,17 @@ macro_rules! uint_impl {
/// ```
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(not(stage0))]
pub fn wrapping_shr(self, rhs: u32) -> Self {
unsafe {
intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT)
}
}

/// Stage 0
#[stable(feature = "num_wrapping", since = "1.2.0")]
#[inline(always)]
#[cfg(stage0)]
pub fn wrapping_shr(self, rhs: u32) -> Self {
self.overflowing_shr(rhs).0
}
Expand Down Expand Up @@ -2170,6 +2232,15 @@ macro_rules! uint_impl {
/// ```
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(not(stage0))]
pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shl(rhs), (rhs > ($BITS - 1)))
}

/// Stage 0
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(stage0)]
pub fn overflowing_shl(self, rhs: u32) -> (Self, bool) {
(self << (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
}
Expand All @@ -2192,6 +2263,16 @@ macro_rules! uint_impl {
/// ```
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(not(stage0))]
pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self.wrapping_shr(rhs), (rhs > ($BITS - 1)))

}

/// Stage 0
#[inline]
#[stable(feature = "wrapping", since = "1.7.0")]
#[cfg(stage0)]
pub fn overflowing_shr(self, rhs: u32) -> (Self, bool) {
(self >> (rhs & ($BITS - 1)), (rhs > ($BITS - 1)))
}
Expand Down Expand Up @@ -2292,7 +2373,7 @@ macro_rules! uint_impl {

#[lang = "u8"]
impl u8 {
uint_impl! { u8, 8,
uint_impl! { u8, u8, 8,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2304,7 +2385,7 @@ impl u8 {

#[lang = "u16"]
impl u16 {
uint_impl! { u16, 16,
uint_impl! { u16, u16, 16,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2316,7 +2397,7 @@ impl u16 {

#[lang = "u32"]
impl u32 {
uint_impl! { u32, 32,
uint_impl! { u32, u32, 32,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2328,7 +2409,7 @@ impl u32 {

#[lang = "u64"]
impl u64 {
uint_impl! { u64, 64,
uint_impl! { u64, u64, 64,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2340,7 +2421,7 @@ impl u64 {

#[lang = "u128"]
impl u128 {
uint_impl! { u128, 128,
uint_impl! { u128, u128, 128,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2353,7 +2434,7 @@ impl u128 {
#[cfg(target_pointer_width = "16")]
#[lang = "usize"]
impl usize {
uint_impl! { u16, 16,
uint_impl! { usize, u16, 16,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2365,7 +2446,7 @@ impl usize {
#[cfg(target_pointer_width = "32")]
#[lang = "usize"]
impl usize {
uint_impl! { u32, 32,
uint_impl! { usize, u32, 32,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand All @@ -2378,7 +2459,7 @@ impl usize {
#[cfg(target_pointer_width = "64")]
#[lang = "usize"]
impl usize {
uint_impl! { u64, 64,
uint_impl! { usize, u64, 64,
intrinsics::ctpop,
intrinsics::ctlz,
intrinsics::cttz,
Expand Down
9 changes: 8 additions & 1 deletion src/librustc_trans/intrinsic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
"ctlz" | "cttz" | "ctpop" | "bswap" |
"add_with_overflow" | "sub_with_overflow" | "mul_with_overflow" |
"overflowing_add" | "overflowing_sub" | "overflowing_mul" |
"unchecked_div" | "unchecked_rem" => {
"unchecked_div" | "unchecked_rem" | "unchecked_shl" | "unchecked_shr" => {
let sty = &arg_tys[0].sty;
match int_type_width_signed(sty, ccx) {
Some((width, signed)) =>
Expand Down Expand Up @@ -311,6 +311,13 @@ pub fn trans_intrinsic_call<'a, 'tcx>(bcx: &Builder<'a, 'tcx>,
} else {
bcx.urem(llargs[0], llargs[1])
},
"unchecked_shl" => bcx.shl(llargs[0], llargs[1]),
"unchecked_shr" =>
if signed {
bcx.ashr(llargs[0], llargs[1])
} else {
bcx.lshr(llargs[0], llargs[1])
},
_ => bug!(),
},
None => {
Expand Down
Loading

0 comments on commit e3cd41a

Please sign in to comment.