Auto merge of #1923 - RalfJung:more-simd, r=RalfJung
More portable SIMD: rem, shl, shr Also make sure we catch the potential UB in div, rem, shl, shr.
This commit is contained in:
commit
73cf2ba0c0
@ -306,7 +306,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
}
|
||||
|
||||
// SIMD operations
|
||||
"simd_add" | "simd_sub" | "simd_mul" | "simd_div" => {
|
||||
#[rustfmt::skip]
|
||||
| "simd_add"
|
||||
| "simd_sub"
|
||||
| "simd_mul"
|
||||
| "simd_div"
|
||||
| "simd_rem"
|
||||
| "simd_shl"
|
||||
| "simd_shr" => {
|
||||
let &[ref left, ref right] = check_arg_count(args)?;
|
||||
let (left, left_len) = this.operand_to_simd(left)?;
|
||||
let (right, right_len) = this.operand_to_simd(right)?;
|
||||
@ -320,14 +327,27 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
|
||||
"simd_sub" => mir::BinOp::Sub,
|
||||
"simd_mul" => mir::BinOp::Mul,
|
||||
"simd_div" => mir::BinOp::Div,
|
||||
"simd_rem" => mir::BinOp::Rem,
|
||||
"simd_shl" => mir::BinOp::Shl,
|
||||
"simd_shr" => mir::BinOp::Shr,
|
||||
_ => unreachable!(),
|
||||
};
|
||||
|
||||
for i in 0..dest_len {
|
||||
let left = this.read_immediate(&this.mplace_index(&left, i)?.into())?;
|
||||
let right = this.read_immediate(&this.mplace_index(&right, i)?.into())?;
|
||||
let dest = this.mplace_index(&dest, i)?.into();
|
||||
this.binop_ignore_overflow(op, &left, &right, &dest)?;
|
||||
let dest = this.mplace_index(&dest, i)?;
|
||||
let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?;
|
||||
assert_eq!(ty, dest.layout.ty);
|
||||
if matches!(op, mir::BinOp::Shl | mir::BinOp::Shr) {
|
||||
// Shifts have extra UB as SIMD operations that the MIR binop does not have.
|
||||
// See <https://github.com/rust-lang/rust/issues/91237>.
|
||||
if overflowed {
|
||||
let r_val = right.to_scalar()?.to_bits(right.layout.size)?;
|
||||
throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i);
|
||||
}
|
||||
}
|
||||
this.write_scalar(val, &dest.into())?;
|
||||
}
|
||||
}
|
||||
|
||||
|
15
tests/compile-fail/intrinsics/simd-div-by-zero.rs
Normal file
15
tests/compile-fail/intrinsics/simd-div-by-zero.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(platform_intrinsics, repr_simd)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
pub(crate) fn simd_div<T>(x: T, y: T) -> T;
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
fn main() { unsafe {
|
||||
let x = i32x2(1, 1);
|
||||
let y = i32x2(1, 0);
|
||||
simd_div(x, y); //~ERROR Undefined Behavior: dividing by zero
|
||||
} }
|
15
tests/compile-fail/intrinsics/simd-rem-by-zero.rs
Normal file
15
tests/compile-fail/intrinsics/simd-rem-by-zero.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(platform_intrinsics, repr_simd)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
pub(crate) fn simd_rem<T>(x: T, y: T) -> T;
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
fn main() { unsafe {
|
||||
let x = i32x2(1, 1);
|
||||
let y = i32x2(1, 0);
|
||||
simd_rem(x, y); //~ERROR Undefined Behavior: calculating the remainder with a divisor of zero
|
||||
} }
|
15
tests/compile-fail/intrinsics/simd-shl-too-far.rs
Normal file
15
tests/compile-fail/intrinsics/simd-shl-too-far.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(platform_intrinsics, repr_simd)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
pub(crate) fn simd_shl<T>(x: T, y: T) -> T;
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
fn main() { unsafe {
|
||||
let x = i32x2(1, 1);
|
||||
let y = i32x2(100, 0);
|
||||
simd_shl(x, y); //~ERROR overflowing shift by 100 in `simd_shl` in SIMD lane 0
|
||||
} }
|
15
tests/compile-fail/intrinsics/simd-shr-too-far.rs
Normal file
15
tests/compile-fail/intrinsics/simd-shr-too-far.rs
Normal file
@ -0,0 +1,15 @@
|
||||
#![feature(platform_intrinsics, repr_simd)]
|
||||
|
||||
extern "platform-intrinsic" {
|
||||
pub(crate) fn simd_shr<T>(x: T, y: T) -> T;
|
||||
}
|
||||
|
||||
#[repr(simd)]
|
||||
#[allow(non_camel_case_types)]
|
||||
struct i32x2(i32, i32);
|
||||
|
||||
fn main() { unsafe {
|
||||
let x = i32x2(1, 1);
|
||||
let y = i32x2(20, 40);
|
||||
simd_shr(x, y); //~ERROR overflowing shift by 40 in `simd_shr` in SIMD lane 1
|
||||
} }
|
@ -9,6 +9,7 @@ fn simd_ops_f32() {
|
||||
assert_eq!(a * b, f32x4::from_array([10.0, 20.0, 30.0, 40.0]));
|
||||
assert_eq!(b / a, f32x4::from_array([0.1, 0.2, 0.3, 0.4]));
|
||||
assert_eq!(a / 2.0, f32x4::splat(5.0));
|
||||
assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0]));
|
||||
}
|
||||
|
||||
fn simd_ops_i32() {
|
||||
@ -19,6 +20,9 @@ fn simd_ops_i32() {
|
||||
assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40]));
|
||||
assert_eq!(a / b, i32x4::from_array([10, 5, 3, 2]));
|
||||
assert_eq!(a / 2, i32x4::splat(5));
|
||||
assert_eq!(a % b, i32x4::from_array([0, 0, 1, 2]));
|
||||
assert_eq!(b << 2, i32x4::from_array([4, 8, 12, 16]));
|
||||
assert_eq!(b >> 1, i32x4::from_array([0, 1, 1, 2]));
|
||||
}
|
||||
|
||||
fn main() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user