Skip to content

Commit 10ec543

Browse files
authored
Merge pull request rust-lang#235 from RalfJung/intrinsics
Implement some missing intrinsics
2 parents fa05ca9 + 19d6ad7 commit 10ec543

12 files changed

+321
-22
lines changed

src/eval_context.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1022,7 +1022,7 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
10221022
fn copy(&mut self, src: PrimVal, dest: PrimVal, ty: Ty<'tcx>) -> EvalResult<'tcx> {
10231023
let size = self.type_size(ty)?.expect("cannot copy from an unsized type");
10241024
let align = self.type_align(ty)?;
1025-
self.memory.copy(src, dest, size, align)?;
1025+
self.memory.copy(src, dest, size, align, false)?;
10261026
Ok(())
10271027
}
10281028

src/memory.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -658,7 +658,7 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
658658
Ok(())
659659
}
660660

661-
pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64) -> EvalResult<'tcx> {
661+
pub fn copy(&mut self, src: PrimVal, dest: PrimVal, size: u64, align: u64, nonoverlapping: bool) -> EvalResult<'tcx> {
662662
if size == 0 {
663663
return Ok(());
664664
}
@@ -675,6 +675,12 @@ impl<'a, 'tcx> Memory<'a, 'tcx> {
675675
unsafe {
676676
assert_eq!(size as usize as u64, size);
677677
if src.alloc_id == dest.alloc_id {
678+
if nonoverlapping {
679+
if (src.offset <= dest.offset && src.offset + size > dest.offset) ||
680+
(dest.offset <= src.offset && dest.offset + size > src.offset) {
681+
return Err(EvalError::Intrinsic(format!("copy_nonoverlapping called on overlapping ranges")));
682+
}
683+
}
678684
ptr::copy(src_bytes, dest_bytes, size as usize);
679685
} else {
680686
ptr::copy_nonoverlapping(src_bytes, dest_bytes, size as usize);

src/operator.rs

Lines changed: 14 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -93,19 +93,20 @@ macro_rules! int_shift {
9393
($kind:expr, $int_op:ident, $l:expr, $r:expr) => ({
9494
let l = $l;
9595
let r = $r;
96+
let r_wrapped = r as u32;
9697
match $kind {
97-
I8 => overflow!($int_op, l as i8, r),
98-
I16 => overflow!($int_op, l as i16, r),
99-
I32 => overflow!($int_op, l as i32, r),
100-
I64 => overflow!($int_op, l as i64, r),
101-
I128 => overflow!($int_op, l as i128, r),
102-
U8 => overflow!($int_op, l as u8, r),
103-
U16 => overflow!($int_op, l as u16, r),
104-
U32 => overflow!($int_op, l as u32, r),
105-
U64 => overflow!($int_op, l as u64, r),
106-
U128 => overflow!($int_op, l as u128, r),
98+
I8 => overflow!($int_op, l as i8, r_wrapped),
99+
I16 => overflow!($int_op, l as i16, r_wrapped),
100+
I32 => overflow!($int_op, l as i32, r_wrapped),
101+
I64 => overflow!($int_op, l as i64, r_wrapped),
102+
I128 => overflow!($int_op, l as i128, r_wrapped),
103+
U8 => overflow!($int_op, l as u8, r_wrapped),
104+
U16 => overflow!($int_op, l as u16, r_wrapped),
105+
U32 => overflow!($int_op, l as u32, r_wrapped),
106+
U64 => overflow!($int_op, l as u64, r_wrapped),
107+
U128 => overflow!($int_op, l as u128, r_wrapped),
107108
_ => bug!("int_shift should only be called on int primvals"),
108-
}
109+
}.map(|(val, over)| (val, over || r != r_wrapped as u128))
109110
})
110111
}
111112

@@ -227,8 +228,8 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
227228
// These ops can have an RHS with a different numeric type.
228229
if right_kind.is_int() && (bin_op == Shl || bin_op == Shr) {
229230
return match bin_op {
230-
Shl => int_shift!(left_kind, overflowing_shl, l, r as u32),
231-
Shr => int_shift!(left_kind, overflowing_shr, l, r as u32),
231+
Shl => int_shift!(left_kind, overflowing_shl, l, r),
232+
Shr => int_shift!(left_kind, overflowing_shr, l, r),
232233
_ => bug!("it has already been checked that this is a shift op"),
233234
};
234235
}

src/terminator/intrinsic.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -140,15 +140,14 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
140140

141141
"copy" |
142142
"copy_nonoverlapping" => {
143-
// FIXME: check whether overlapping occurs
144143
let elem_ty = substs.type_at(0);
145144
let elem_size = self.type_size(elem_ty)?.expect("cannot copy unsized value");
146145
if elem_size != 0 {
147146
let elem_align = self.type_align(elem_ty)?;
148147
let src = arg_vals[0].read_ptr(&self.memory)?;
149148
let dest = arg_vals[1].read_ptr(&self.memory)?;
150149
let count = self.value_to_primval(arg_vals[2], usize)?.to_u64()?;
151-
self.memory.copy(src, dest, count * elem_size, elem_align)?;
150+
self.memory.copy(src, dest, count * elem_size, elem_align, intrinsic_name.ends_with("_nonoverlapping"))?;
152151
}
153152
}
154153

@@ -401,6 +400,40 @@ impl<'a, 'tcx> EvalContext<'a, 'tcx> {
401400
self.write_value_to_ptr(arg_vals[0], PrimVal::Ptr(ptr), src_ty)?;
402401
}
403402

403+
"unchecked_shl" => {
404+
let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8;
405+
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
406+
if rhs >= bits {
407+
return Err(EvalError::Intrinsic(format!("Overflowing shift by {} in unchecked_shl", rhs)));
408+
}
409+
self.intrinsic_overflowing(mir::BinOp::Shl, &args[0], &args[1], dest, dest_ty)?;
410+
}
411+
412+
"unchecked_shr" => {
413+
let bits = self.type_size(dest_ty)?.expect("intrinsic can't be called on unsized type") as u128 * 8;
414+
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
415+
if rhs >= bits {
416+
return Err(EvalError::Intrinsic(format!("Overflowing shift by {} in unchecked_shr", rhs)));
417+
}
418+
self.intrinsic_overflowing(mir::BinOp::Shr, &args[0], &args[1], dest, dest_ty)?;
419+
}
420+
421+
"unchecked_div" => {
422+
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
423+
if rhs == 0 {
424+
return Err(EvalError::Intrinsic(format!("Division by 0 in unchecked_div")));
425+
}
426+
self.intrinsic_overflowing(mir::BinOp::Div, &args[0], &args[1], dest, dest_ty)?;
427+
}
428+
429+
"unchecked_rem" => {
430+
let rhs = self.value_to_primval(arg_vals[1], substs.type_at(0))?.to_bytes()?;
431+
if rhs == 0 {
432+
return Err(EvalError::Intrinsic(format!("Division by 0 in unchecked_rem")));
433+
}
434+
self.intrinsic_overflowing(mir::BinOp::Rem, &args[0], &args[1], dest, dest_ty)?;
435+
}
436+
404437
"uninit" => {
405438
let size = dest_layout.size(&self.tcx.data_layout).bytes();
406439
let uninit = |this: &mut Self, val: Value| {
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(core_intrinsics)]
12+
13+
use std::intrinsics::*;
14+
15+
//error-pattern: copy_nonoverlapping called on overlapping ranges
16+
17+
fn main() {
18+
let mut data = [0u8; 16];
19+
unsafe {
20+
let a = &data[0] as *const _;
21+
let b = &mut data[1] as *mut _;
22+
std::ptr::copy_nonoverlapping(a, b, 2);
23+
}
24+
}

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

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(const_err)]
12+
13+
fn main() {
14+
let _n = 1 / 0; //~ ERROR: DivisionByZero
15+
}

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

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(core_intrinsics)]
12+
13+
use std::intrinsics::*;
14+
15+
//error-pattern: Division by 0 in unchecked_div
16+
17+
fn main() {
18+
unsafe {
19+
let _n = unchecked_div(1i64, 0);
20+
}
21+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![allow(exceeding_bitshifts, const_err)]
12+
13+
fn main() {
14+
// Make sure we catch overflows that would be hidden by first casting the RHS to u32
15+
let _n = 1i64 >> (u32::max_value() as i64 + 1); //~ Overflow(Shr)
16+
}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
#![feature(core_intrinsics)]
12+
13+
use std::intrinsics::*;
14+
15+
//error-pattern: Overflowing shift by 64 in unchecked_shr
16+
17+
fn main() {
18+
unsafe {
19+
let _n = unchecked_shr(1i64, 64);
20+
}
21+
}

0 commit comments

Comments
 (0)