Skip to content

Commit e4b298b

Browse files
authored
Merge pull request #776 from RalfJung/intrinsics
implement unchecked_{add,sub,mul} intrinsics
2 parents 14c4192 + 7ce3622 commit e4b298b

13 files changed

+110
-15
lines changed

src/intrinsic.rs

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -272,7 +272,13 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
272272
let b = this.read_immediate(args[1])?;
273273
// check x % y != 0
274274
if this.binary_op(mir::BinOp::Rem, a, b)?.0.to_bits(dest.layout.size)? != 0 {
275-
return err!(ValidationFailure(format!("exact_div: {:?} cannot be divided by {:?}", a, b)));
275+
// Check if `b` is -1, which is the "min_value / -1" case.
276+
let minus1 = Scalar::from_int(-1, dest.layout.size);
277+
return if b.to_scalar().unwrap() == minus1 {
278+
err!(Intrinsic(format!("exact_div: result of dividing MIN by -1 cannot be represented")))
279+
} else {
280+
err!(Intrinsic(format!("exact_div: {:?} cannot be divided by {:?} without remainder", *a, *b)))
281+
};
276282
}
277283
this.binop_ignore_overflow(mir::BinOp::Div, a, b, dest)?;
278284
},
@@ -459,6 +465,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
459465
)?;
460466
}
461467

468+
"unchecked_add" | "unchecked_sub" | "unchecked_mul" => {
469+
let l = this.read_immediate(args[0])?;
470+
let r = this.read_immediate(args[1])?;
471+
let op = match intrinsic_name.get() {
472+
"unchecked_add" => mir::BinOp::Add,
473+
"unchecked_sub" => mir::BinOp::Sub,
474+
"unchecked_mul" => mir::BinOp::Mul,
475+
_ => bug!(),
476+
};
477+
let (res, overflowed) = this.binary_op(op, l, r)?;
478+
if overflowed {
479+
return err!(Intrinsic(format!("Overflowing arithmetic in {}", intrinsic_name.get())));
480+
}
481+
this.write_scalar(res, dest)?;
482+
}
483+
462484
"uninit" => {
463485
// Check fast path: we don't want to force an allocation in case the destination is a simple value,
464486
// but we also do not want to create a new allocation with 0s and then copy that over.

tests/compile-fail/div-by-zero-3.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
#![feature(core_intrinsics)]
2+
3+
use std::intrinsics::*;
4+
5+
//error-pattern: Division by 0 in unchecked_rem
6+
7+
fn main() {
8+
unsafe {
9+
let _n = unchecked_rem(3u32, 0);
10+
}
11+
}

tests/compile-fail/exact_div1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// divison by 0
4+
unsafe { std::intrinsics::exact_div(2, 0); } //~ ERROR divisor of zero
5+
}

tests/compile-fail/exact_div2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// divison with a remainder
4+
unsafe { std::intrinsics::exact_div(2u16, 3); } //~ ERROR Scalar(0x0002) cannot be divided by Scalar(0x0003) without remainder
5+
}

tests/compile-fail/exact_div3.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// signed divison with a remainder
4+
unsafe { std::intrinsics::exact_div(-19i8, 2); } //~ ERROR Scalar(0xed) cannot be divided by Scalar(0x02) without remainder
5+
}

tests/compile-fail/exact_div4.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// divison of min_value by -1
4+
unsafe { std::intrinsics::exact_div(i64::min_value(), -1); } //~ ERROR result of dividing MIN by -1 cannot be represented
5+
}

tests/compile-fail/unchecked_add1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MAX overflow
4+
unsafe { std::intrinsics::unchecked_add(40000u16, 30000); } //~ ERROR Overflowing arithmetic in unchecked_add
5+
}

tests/compile-fail/unchecked_add2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MIN overflow
4+
unsafe { std::intrinsics::unchecked_add(-30000i16, -8000); } //~ ERROR Overflowing arithmetic in unchecked_add
5+
}

tests/compile-fail/unchecked_mul1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MAX overflow
4+
unsafe { std::intrinsics::unchecked_mul(300u16, 250u16); } //~ ERROR Overflowing arithmetic in unchecked_mul
5+
}

tests/compile-fail/unchecked_mul2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MIN overflow
4+
unsafe { std::intrinsics::unchecked_mul(1_000_000_000i32, -4); } //~ ERROR Overflowing arithmetic in unchecked_mul
5+
}

tests/compile-fail/unchecked_sub1.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MIN overflow
4+
unsafe { std::intrinsics::unchecked_sub(14u32, 22); } //~ ERROR Overflowing arithmetic in unchecked_sub
5+
}

tests/compile-fail/unchecked_sub2.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
#![feature(core_intrinsics)]
2+
fn main() {
3+
// MAX overflow
4+
unsafe { std::intrinsics::unchecked_sub(30000i16, -7000); } //~ ERROR Overflowing arithmetic in unchecked_sub
5+
}

tests/run-pass/intrinsics-integer.rs

Lines changed: 26 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -8,23 +8,11 @@
88
// option. This file may not be copied, modified, or distributed
99
// except according to those terms.
1010

11-
#![feature(intrinsics)]
12-
13-
mod rusti {
14-
extern "rust-intrinsic" {
15-
pub fn ctpop<T>(x: T) -> T;
16-
pub fn ctlz<T>(x: T) -> T;
17-
pub fn ctlz_nonzero<T>(x: T) -> T;
18-
pub fn cttz<T>(x: T) -> T;
19-
pub fn cttz_nonzero<T>(x: T) -> T;
20-
pub fn bswap<T>(x: T) -> T;
21-
}
22-
}
11+
#![feature(core_intrinsics)]
12+
use std::intrinsics::*;
2313

2414
pub fn main() {
2515
unsafe {
26-
use crate::rusti::*;
27-
2816
assert_eq!(ctpop(0u8), 0); assert_eq!(ctpop(0i8), 0);
2917
assert_eq!(ctpop(0u16), 0); assert_eq!(ctpop(0i16), 0);
3018
assert_eq!(ctpop(0u32), 0); assert_eq!(ctpop(0i32), 0);
@@ -138,5 +126,29 @@ pub fn main() {
138126
assert_eq!(bswap(0x0ABBCC0Di32), 0x0DCCBB0A);
139127
assert_eq!(bswap(0x0122334455667708u64), 0x0877665544332201);
140128
assert_eq!(bswap(0x0122334455667708i64), 0x0877665544332201);
129+
130+
assert_eq!(exact_div(9*9u32, 3), 27);
131+
assert_eq!(exact_div(-9*9i32, 3), -27);
132+
assert_eq!(exact_div(9*9i8, -3), -27);
133+
assert_eq!(exact_div(-9*9i64, -3), 27);
134+
135+
assert_eq!(unchecked_div(9*9u32, 2), 40);
136+
assert_eq!(unchecked_div(-9*9i32, 2), -40);
137+
assert_eq!(unchecked_div(9*9i8, -2), -40);
138+
assert_eq!(unchecked_div(-9*9i64, -2), 40);
139+
140+
assert_eq!(unchecked_rem(9*9u32, 2), 1);
141+
assert_eq!(unchecked_rem(-9*9i32, 2), -1);
142+
assert_eq!(unchecked_rem(9*9i8, -2), 1);
143+
assert_eq!(unchecked_rem(-9*9i64, -2), -1);
144+
145+
assert_eq!(unchecked_add(23u8, 19), 42);
146+
assert_eq!(unchecked_add(5, -10), -5);
147+
148+
assert_eq!(unchecked_sub(23u8, 19), 4);
149+
assert_eq!(unchecked_sub(-17, -27), 10);
150+
151+
assert_eq!(unchecked_mul(6u8, 7), 42);
152+
assert_eq!(unchecked_mul(13, -5), -65);
141153
}
142154
}

0 commit comments

Comments
 (0)