diff --git a/src/lib.rs b/src/lib.rs index 006eedde4b6..9542fb9b963 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -3,6 +3,7 @@ #![feature(map_try_insert)] #![feature(never_type)] #![feature(try_blocks)] +#![feature(let_else)] #![feature(bool_to_option)] #![warn(rust_2018_idioms)] #![allow(clippy::cast_lossless)] diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index e8492331418..f713721f584 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -316,6 +316,37 @@ fn call_intrinsic( // SIMD operations #[rustfmt::skip] + | "simd_neg" + | "simd_fabs" => { + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; + let (dest, dest_len) = this.place_to_simd(dest)?; + + assert_eq!(dest_len, op_len); + + for i in 0..dest_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; + let dest = this.mplace_index(&dest, i)?; + let val = match intrinsic_name { + "simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?, + "simd_fabs" => { + // Works for f32 and f64. + let ty::Float(float_ty) = op.layout.ty.kind() else { + bug!("simd_fabs operand is not a float") + }; + let op = op.to_scalar()?; + // FIXME: Using host floats. + match float_ty { + FloatTy::F32 => Scalar::from_f32(op.to_f32()?.abs()), + FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), + } + } + _ => bug!(), + }; + this.write_scalar(val, &dest.into())?; + } + } + #[rustfmt::skip] | "simd_add" | "simd_sub" | "simd_mul" @@ -374,12 +405,12 @@ fn call_intrinsic( } } "simd_reduce_any" => { - let &[ref arg] = check_arg_count(args)?; - let (arg, arg_len) = this.operand_to_simd(arg)?; + let &[ref op] = check_arg_count(args)?; + let (op, op_len) = this.operand_to_simd(op)?; let mut res = false; // the neutral element - for i in 0..arg_len { - let op = this.read_immediate(&this.mplace_index(&arg, i)?.into())?; + for i in 0..op_len { + let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?; let val = simd_element_to_bool(op)?; res = res | val; } diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index 98d5b65e3e6..c0c1ecd0235 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -3,18 +3,34 @@ fn simd_ops_f32() { let a = f32x4::splat(10.0); - let b = f32x4::from_array([1.0, 2.0, 3.0, 4.0]); - assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 14.0])); - assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 6.0])); - 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])); + let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f32x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f32x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f32x4::from_array([9.0, 8.0, 7.0, 14.0])); + 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 / f32x4::splat(2.0), f32x4::splat(5.0)); assert_eq!(a % b, f32x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f32x4::from_array([1.0, 2.0, 3.0, 4.0])); +} + +fn simd_ops_f64() { + let a = f64x4::splat(10.0); + let b = f64x4::from_array([1.0, 2.0, 3.0, -4.0]); + assert_eq!(-b, f64x4::from_array([-1.0, -2.0, -3.0, 4.0])); + assert_eq!(a + b, f64x4::from_array([11.0, 12.0, 13.0, 6.0])); + assert_eq!(a - b, f64x4::from_array([9.0, 8.0, 7.0, 14.0])); + assert_eq!(a * b, f64x4::from_array([10.0, 20.0, 30.0, -40.0])); + assert_eq!(b / a, f64x4::from_array([0.1, 0.2, 0.3, -0.4])); + assert_eq!(a / f64x4::splat(2.0), f64x4::splat(5.0)); + assert_eq!(a % b, f64x4::from_array([0.0, 0.0, 1.0, 2.0])); + assert_eq!(b.abs(), f64x4::from_array([1.0, 2.0, 3.0, 4.0])); } fn simd_ops_i32() { let a = i32x4::splat(10); let b = i32x4::from_array([1, 2, 3, 4]); + assert_eq!(-b, i32x4::from_array([-1, -2, -3, -4])); assert_eq!(a + b, i32x4::from_array([11, 12, 13, 14])); assert_eq!(a - b, i32x4::from_array([9, 8, 7, 6])); assert_eq!(a * b, i32x4::from_array([10, 20, 30, 40])); @@ -52,6 +68,7 @@ fn simd_intrinsics() { fn main() { simd_ops_f32(); + simd_ops_f64(); simd_ops_i32(); simd_intrinsics(); }