Skip to content

Commit

Permalink
implement shl and shr SIMD intrinsics
Browse files Browse the repository at this point in the history
  • Loading branch information
RalfJung committed Nov 25, 2021
1 parent a534bbb commit 4414d96
Show file tree
Hide file tree
Showing 4 changed files with 54 additions and 3 deletions.
25 changes: 22 additions & 3 deletions src/shims/intrinsics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -306,7 +306,14 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
}

// SIMD operations
"simd_add" | "simd_sub" | "simd_mul" | "simd_div" | "simd_rem" => {
#[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)?;
Expand All @@ -321,14 +328,26 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
"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())?;
}
}

Expand Down
15 changes: 15 additions & 0 deletions tests/compile-fail/intrinsics/simd-shl-too-far.rs
Original file line number Diff line number Diff line change
@@ -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 changes: 15 additions & 0 deletions tests/compile-fail/intrinsics/simd-shr-too-far.rs
Original file line number Diff line number Diff line change
@@ -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
} }
2 changes: 2 additions & 0 deletions tests/run-pass/portable-simd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ fn simd_ops_i32() {
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() {
Expand Down

0 comments on commit 4414d96

Please sign in to comment.