From 3ed8ad4423684a006e8db194c91f585798b500ab Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Sat, 5 Mar 2022 18:46:14 -0500 Subject: [PATCH] avoid repeated string matching, and add more simd_reduce intrinsics --- src/machine.rs | 2 ++ src/shims/intrinsics.rs | 62 ++++++++++++++++++++++++--------- tests/run-pass/portable-simd.rs | 7 ++++ 3 files changed, 55 insertions(+), 16 deletions(-) diff --git a/src/machine.rs b/src/machine.rs index a75ac844902..481808dc781 100644 --- a/src/machine.rs +++ b/src/machine.rs @@ -267,6 +267,7 @@ pub struct PrimitiveLayouts<'tcx> { pub u8: TyAndLayout<'tcx>, pub u32: TyAndLayout<'tcx>, pub usize: TyAndLayout<'tcx>, + pub bool: TyAndLayout<'tcx>, } impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { @@ -279,6 +280,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> { u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?, u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?, usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?, + bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?, }) } } diff --git a/src/shims/intrinsics.rs b/src/shims/intrinsics.rs index 5bebc52b782..532eb08b191 100644 --- a/src/shims/intrinsics.rs +++ b/src/shims/intrinsics.rs @@ -324,12 +324,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx assert_eq!(dest_len, op_len); + enum Op { + MirOp(mir::UnOp), + Abs, + } + let which = match intrinsic_name { + "simd_neg" => Op::MirOp(mir::UnOp::Neg), + "simd_fabs" => Op::Abs, + _ => unreachable!(), + }; + 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" => { + let val = match which { + Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?, + Op::Abs => { // Works for f32 and f64. let ty::Float(float_ty) = op.layout.ty.kind() else { bug!("simd_fabs operand is not a float") @@ -341,7 +351,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()), } } - _ => bug!(), }; this.write_scalar(val, &dest.into())?; } @@ -419,28 +428,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx } } } - "simd_reduce_any" | "simd_reduce_all" => { + #[rustfmt::skip] + | "simd_reduce_and" + | "simd_reduce_or" + | "simd_reduce_xor" + | "simd_reduce_any" + | "simd_reduce_all" => { + use mir::BinOp; + let &[ref op] = check_arg_count(args)?; let (op, op_len) = this.operand_to_simd(op)?; - // the neutral element - let mut res = match intrinsic_name { - "simd_reduce_any" => false, - "simd_reduce_all" => true, - _ => bug!(), + let imm_from_bool = + |b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool); + + enum Op { + MirOp(BinOp), + MirOpBool(BinOp), + } + // The initial value is the neutral element. + let (which, init) = match intrinsic_name { + "simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)), + "simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)), + "simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)), + "simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)), + "simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)), + _ => unreachable!(), }; + let mut res = init; 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 = match intrinsic_name { - "simd_reduce_any" => res | val, - "simd_reduce_all" => res & val, - _ => bug!(), + res = match which { + Op::MirOp(mir_op) => { + this.binary_op(mir_op, &res, &op)? + } + Op::MirOpBool(mir_op) => { + let op = imm_from_bool(simd_element_to_bool(op)?); + this.binary_op(mir_op, &res, &op)? + } }; } - this.write_scalar(Scalar::from_bool(res), dest)?; + this.write_immediate(*res, dest)?; } "simd_select" => { let &[ref mask, ref yes, ref no] = check_arg_count(args)?; diff --git a/tests/run-pass/portable-simd.rs b/tests/run-pass/portable-simd.rs index d43e7be8b19..ef8a5752b7c 100644 --- a/tests/run-pass/portable-simd.rs +++ b/tests/run-pass/portable-simd.rs @@ -68,6 +68,13 @@ fn simd_ops_i32() { assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0]))); assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1]))); assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1]))); + + assert_eq!(a.horizontal_and(), 10); + assert_eq!(b.horizontal_and(), 0); + assert_eq!(a.horizontal_or(), 10); + assert_eq!(b.horizontal_or(), -1); + assert_eq!(a.horizontal_xor(), 0); + assert_eq!(b.horizontal_xor(), -4); } fn simd_intrinsics() {