]> git.lizzy.rs Git - rust.git/commitdiff
avoid repeated string matching, and add more simd_reduce intrinsics
authorRalf Jung <post@ralfj.de>
Sat, 5 Mar 2022 23:46:14 +0000 (18:46 -0500)
committerRalf Jung <post@ralfj.de>
Sat, 5 Mar 2022 23:46:14 +0000 (18:46 -0500)
src/machine.rs
src/shims/intrinsics.rs
tests/run-pass/portable-simd.rs

index a75ac844902fc507b96769e95a57db8b0f4d47ce..481808dc78197992c31db3a27cbe2fc8e922dd61 100644 (file)
@@ -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 @@ fn new(layout_cx: LayoutCx<'tcx, TyCtxt<'tcx>>) -> Result<Self, LayoutError<'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)?,
         })
     }
 }
index 5bebc52b78285c8d542d98d132fcb69985ccb67a..532eb08b191b016960a30a94fc69f5934bc35bbb 100644 (file)
@@ -324,12 +324,22 @@ fn call_intrinsic(
 
                 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 @@ fn call_intrinsic(
                                 FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
                             }
                         }
-                        _ => bug!(),
                     };
                     this.write_scalar(val, &dest.into())?;
                 }
@@ -419,28 +428,49 @@ fn call_intrinsic(
                     }
                 }
             }
-            "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)?;
index d43e7be8b192170a66b324da897e962f76b33f54..ef8a5752b7cc71f1e6042403ed0a729ebadece02 100644 (file)
@@ -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() {