let b = this.read_immediate(args[1])?;
// check x % y != 0
if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
- return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b)));
+ // Check if `b` is -1, which is the "min_value / -1" case.
+ let minus1 = Scalar::from_int(-1, dest.layout.size);
+ return if b.to_scalar().unwrap() == minus1 {
+ err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented")))
+ } else {
+ err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b)))
+ };
}
this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?;
},
)?;
}
+ "unchecked_add" | "unchecked_sub" | "unchecked_mul" => {
+ let l = this.read_immediate(args[0])?;
+ let r = this.read_immediate(args[1])?;
+ let op = match intrinsic_name.get() {
+ "unchecked_add" => mir::BinOp::Add,
+ "unchecked_sub" => mir::BinOp::Sub,
+ "unchecked_mul" => mir::BinOp::Mul,
+ _ => bug!(),
+ };
+ let (res, overflowed) = this.binary_op(op, l, r)?;
+ if overflowed {
+ return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get())));
+ }
+ this.write_scalar(res, dest)?;
+ }
+
"uninit" => {
// Check fast path: we don't want to force an allocation in case the destination is a simple value,
// but we also do not want to create a new allocation with 0s and then copy that over.
--- /dev/null
+#![feature(core_intrinsics)]
+
+use std::intrinsics::*;
+
+//error-pattern: Division by 0 in unchecked_rem
+
+fn main() {
+ unsafe {
+ let _n = unchecked_rem(3u32, 0);
+ }
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // divison by 0
+ unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // divison with a remainder
+ unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // signed divison with a remainder
+ unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // divison of min_value by -1
+ unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MAX overflow
+ unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MIN overflow
+ unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MAX overflow
+ unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MIN overflow
+ unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MIN overflow
+ unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub
+}
--- /dev/null
+#![feature(core_intrinsics)]
+fn main() {
+ // MAX overflow
+ unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub
+}
// option. This file may not be copied, modified, or distributed
// except according to those terms.
-#![feature(intrinsics)]
-
-mod rusti {
- extern "rust-intrinsic" {
- pub fn ctpop<T>(x: T) -> T;
- pub fn ctlz<T>(x: T) -> T;
- pub fn ctlz_nonzero<T>(x: T) -> T;
- pub fn cttz<T>(x: T) -> T;
- pub fn cttz_nonzero<T>(x: T) -> T;
- pub fn bswap<T>(x: T) -> T;
- }
-}
+#![feature(core_intrinsics)]
+use std::intrinsics::*;
pub fn main() {
unsafe {
- use crate::rusti::*;
-
assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0);
assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0);
assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0);
assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A);
assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201);
assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201);
+
+ assert_eq!(exact_div(9*9u32, 3), 27);
+ assert_eq!(exact_div(-9*9i32, 3), -27);
+ assert_eq!(exact_div(9*9i8, -3), -27);
+ assert_eq!(exact_div(-9*9i64, -3), 27);
+
+ assert_eq!(unchecked_div(9*9u32, 2), 40);
+ assert_eq!(unchecked_div(-9*9i32, 2), -40);
+ assert_eq!(unchecked_div(9*9i8, -2), -40);
+ assert_eq!(unchecked_div(-9*9i64, -2), 40);
+
+ assert_eq!(unchecked_rem(9*9u32, 2), 1);
+ assert_eq!(unchecked_rem(-9*9i32, 2), -1);
+ assert_eq!(unchecked_rem(9*9i8, -2), 1);
+ assert_eq!(unchecked_rem(-9*9i64, -2), -1);
+
+ assert_eq!(unchecked_add(23u8, 19), 42);
+ assert_eq!(unchecked_add(5, -10), -5);
+
+ assert_eq!(unchecked_sub(23u8, 19), 4);
+ assert_eq!(unchecked_sub(-17, -27), 10);
+
+ assert_eq!(unchecked_mul(6u8, 7), 42);
+ assert_eq!(unchecked_mul(13, -5), -65);
}
}