From f118ff43e7208338fa44567725e7a2af90b60a86 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Mon, 3 Jul 2017 19:55:15 -0700 Subject: [PATCH] implement the unchecked_ intrinsics; add all the doctests from one of the integer modules --- src/operator.rs | 1 + src/terminator/intrinsic.rs | 26 ++++ tests/run-pass-fullmir/integer-ops.rs | 167 ++++++++++++++++++++++++++ tests/run-pass-fullmir/u128.rs | 4 +- 4 files changed, 196 insertions(+), 2 deletions(-) create mode 100644 tests/run-pass-fullmir/integer-ops.rs diff --git a/src/operator.rs b/src/operator.rs index 5386fa588a4..35d3ab213af 100644 --- a/src/operator.rs +++ b/src/operator.rs @@ -226,6 +226,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { // These ops can have an RHS with a different numeric type. if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) { + // FIXME: The "as u32" here could hide an overflow return match bin_op { Shl => int_shift!(left_kind, overflowing_shl, l, r as u32), Shr => int_shift!(left_kind, overflowing_shr, l, r as u32), diff --git a/src/terminator/intrinsic.rs b/src/terminator/intrinsic.rs index 360842ac547..ae2d0b4f5de 100644 --- a/src/terminator/intrinsic.rs +++ b/src/terminator/intrinsic.rs @@ -407,6 +407,32 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> { } } + "unchecked_shl" => { + // FIXME Check for too-wide shifts + self.intrinsic_overflowing(mir::BinOp::Shl, &args[0], &args[1], dest, dest_ty)?; + } + + "unchecked_shr" => { + // FIXME Check for too-wide shifts + self.intrinsic_overflowing(mir::BinOp::Shr, &args[0], &args[1], dest, dest_ty)?; + } + + "unchecked_div" => { + let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?; + if rhs == 0 { + return Err(EvalError::Intrinsic(format!("Division by 0 in unchecked_div"))); + } + self.intrinsic_overflowing(mir::BinOp::Div, &args[0], &args[1], dest, dest_ty)?; + } + + "unchecked_rem" => { + let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?; + if rhs == 0 { + return Err(EvalError::Intrinsic(format!("Division by 0 in unchecked_rem"))); + } + self.intrinsic_overflowing(mir::BinOp::Rem, &args[0], &args[1], dest, dest_ty)?; + } + "uninit" => { let size = dest_layout.size(&self.tcx.data_layout).bytes(); let uninit = |this: &mut Self, val: Value| { diff --git a/tests/run-pass-fullmir/integer-ops.rs b/tests/run-pass-fullmir/integer-ops.rs new file mode 100644 index 00000000000..3773e699ddf --- /dev/null +++ b/tests/run-pass-fullmir/integer-ops.rs @@ -0,0 +1,167 @@ +// Copyright 2012-2014 The Rust Project Developers. See the COPYRIGHT +// file at the top-level directory of this distribution and at +// http://rust-lang.org/COPYRIGHT. +// +// Licensed under the Apache License, Version 2.0 or the MIT license +// , at your +// option. This file may not be copied, modified, or distributed +// except according to those terms. + +use std::i32; + +pub fn main() { + assert_eq!(i8::min_value(), -128); + + assert_eq!(i8::max_value(), 127); + + assert_eq!(i32::from_str_radix("A", 16), Ok(10)); + + let n = -0b1000_0000i8; + assert_eq!(n.count_ones(), 1); + + let n = -0b1000_0000i8; + assert_eq!(n.count_zeros(), 7); + + let n = -1i16; + assert_eq!(n.leading_zeros(), 0); + + let n = -4i8; + assert_eq!(n.trailing_zeros(), 2); + + let n = 0x0123456789ABCDEFi64; + let m = -0x76543210FEDCBA99i64; + assert_eq!(n.rotate_left(32), m); + + let n = 0x0123456789ABCDEFi64; + let m = -0xFEDCBA987654322i64; + assert_eq!(n.rotate_right(4), m); + + let n = 0x0123456789ABCDEFi64; + let m = -0x1032547698BADCFFi64; + assert_eq!(n.swap_bytes(), m); + + let n = 0x0123456789ABCDEFi64; + if cfg!(target_endian = "big") { + assert_eq!(i64::from_be(n), n) + } else { + assert_eq!(i64::from_be(n), n.swap_bytes()) + } + + let n = 0x0123456789ABCDEFi64; + if cfg!(target_endian = "little") { + assert_eq!(i64::from_le(n), n) + } else { + assert_eq!(i64::from_le(n), n.swap_bytes()) + } + + let n = 0x0123456789ABCDEFi64; + if cfg!(target_endian = "big") { + assert_eq!(n.to_be(), n) + } else { + assert_eq!(n.to_be(), n.swap_bytes()) + } + + let n = 0x0123456789ABCDEFi64; + if cfg!(target_endian = "little") { + assert_eq!(n.to_le(), n) + } else { + assert_eq!(n.to_le(), n.swap_bytes()) + } + + assert_eq!(7i16.checked_add(32760), Some(32767)); + assert_eq!(8i16.checked_add(32760), None); + + assert_eq!((-127i8).checked_sub(1), Some(-128)); + assert_eq!((-128i8).checked_sub(1), None); + + assert_eq!(6i8.checked_mul(21), Some(126)); + assert_eq!(6i8.checked_mul(22), None); + + assert_eq!((-127i8).checked_div(-1), Some(127)); + assert_eq!((-128i8).checked_div(-1), None); + assert_eq!((1i8).checked_div(0), None); + + assert_eq!(5i32.checked_rem(2), Some(1)); + assert_eq!(5i32.checked_rem(0), None); + assert_eq!(i32::MIN.checked_rem(-1), None); + + assert_eq!(5i32.checked_neg(), Some(-5)); + assert_eq!(i32::MIN.checked_neg(), None); + + assert_eq!(0x10i32.checked_shl(4), Some(0x100)); + assert_eq!(0x10i32.checked_shl(33), None); + + assert_eq!(0x10i32.checked_shr(4), Some(0x1)); + assert_eq!(0x10i32.checked_shr(33), None); + + assert_eq!((-5i32).checked_abs(), Some(5)); + assert_eq!(i32::MIN.checked_abs(), None); + + assert_eq!(100i8.saturating_add(1), 101); + assert_eq!(100i8.saturating_add(127), 127); + + assert_eq!(100i8.saturating_sub(127), -27); + assert_eq!((-100i8).saturating_sub(127), -128); + + assert_eq!(100i32.saturating_mul(127), 12700); + assert_eq!((1i32 << 23).saturating_mul(1 << 23), i32::MAX); + assert_eq!((-1i32 << 23).saturating_mul(1 << 23), i32::MIN); + + assert_eq!(100i8.wrapping_add(27), 127); + assert_eq!(100i8.wrapping_add(127), -29); + + assert_eq!(0i8.wrapping_sub(127), -127); + assert_eq!((-2i8).wrapping_sub(127), 127); + + assert_eq!(10i8.wrapping_mul(12), 120); + assert_eq!(11i8.wrapping_mul(12), -124); + + assert_eq!(100u8.wrapping_div(10), 10); + assert_eq!((-128i8).wrapping_div(-1), -128); + + assert_eq!(100i8.wrapping_rem(10), 0); + assert_eq!((-128i8).wrapping_rem(-1), 0); + + assert_eq!(100i8.wrapping_neg(), -100); + assert_eq!((-128i8).wrapping_neg(), -128); + + assert_eq!((-1i8).wrapping_shl(7), -128); + assert_eq!((-1i8).wrapping_shl(8), -1); + + assert_eq!((-128i8).wrapping_shr(7), -1); + assert_eq!((-128i8).wrapping_shr(8), -128); + + assert_eq!(100i8.wrapping_abs(), 100); + assert_eq!((-100i8).wrapping_abs(), 100); + assert_eq!((-128i8).wrapping_abs(), -128); + assert_eq!((-128i8).wrapping_abs() as u8, 128); + + assert_eq!(5i32.overflowing_add(2), (7, false)); + assert_eq!(i32::MAX.overflowing_add(1), (i32::MIN, true)); + + assert_eq!(5i32.overflowing_sub(2), (3, false)); + assert_eq!(i32::MIN.overflowing_sub(1), (i32::MAX, true)); + + assert_eq!(5i32.overflowing_mul(2), (10, false)); + assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true)); + + assert_eq!(5i32.overflowing_div(2), (2, false)); + assert_eq!(i32::MIN.overflowing_div(-1), (i32::MIN, true)); + + assert_eq!(5i32.overflowing_rem(2), (1, false)); + assert_eq!(i32::MIN.overflowing_rem(-1), (0, true)); + + assert_eq!(2i32.overflowing_neg(), (-2, false)); + assert_eq!(i32::MIN.overflowing_neg(), (i32::MIN, true)); + + assert_eq!(0x10i32.overflowing_shl(4), (0x100, false)); + assert_eq!(0x10i32.overflowing_shl(36), (0x100, true)); + + assert_eq!(0x10i32.overflowing_shr(4), (0x1, false)); + assert_eq!(0x10i32.overflowing_shr(36), (0x1, true)); + + assert_eq!(10i8.overflowing_abs(), (10,false)); + assert_eq!((-10i8).overflowing_abs(), (10,false)); + assert_eq!((-128i8).overflowing_abs(), (-128,true)); +} diff --git a/tests/run-pass-fullmir/u128.rs b/tests/run-pass-fullmir/u128.rs index 6cad0cf3ec4..a05308acbe6 100644 --- a/tests/run-pass-fullmir/u128.rs +++ b/tests/run-pass-fullmir/u128.rs @@ -72,6 +72,6 @@ fn main() { assert_eq!(l.checked_add(b(11)), None); assert_eq!(l.checked_sub(l), Some(0)); assert_eq!(o.checked_sub(b(18)), None); - //assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); - //assert_eq!(o.checked_shl(b(128)), None); + assert_eq!(b(1u128).checked_shl(b(127)), Some(1 << 127)); + assert_eq!(o.checked_shl(b(128)), None); }