]> git.lizzy.rs Git - rust.git/commitdiff
implement simd_reduce_{add,mul}
authorRalf Jung <post@ralfj.de>
Sun, 6 Mar 2022 00:02:00 +0000 (19:02 -0500)
committerRalf Jung <post@ralfj.de>
Sun, 6 Mar 2022 00:02:00 +0000 (19:02 -0500)
src/shims/intrinsics.rs
tests/run-pass/portable-simd.rs

index 532eb08b191b016960a30a94fc69f5934bc35bbb..670e3cb1b8acb7ab616801148570ca3009bd1f0b 100644 (file)
@@ -382,7 +382,7 @@ enum Op {
                 assert_eq!(dest_len, left_len);
                 assert_eq!(dest_len, right_len);
 
-                let op = match intrinsic_name {
+                let mir_op = match intrinsic_name {
                     "simd_add" => BinOp::Add,
                     "simd_sub" => BinOp::Sub,
                     "simd_mul" => BinOp::Mul,
@@ -406,8 +406,8 @@ enum Op {
                     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)?;
-                    let (val, overflowed, ty) = this.overflowing_binary_op(op, &left, &right)?;
-                    if matches!(op, BinOp::Shl | BinOp::Shr) {
+                    let (val, overflowed, ty) = this.overflowing_binary_op(mir_op, &left, &right)?;
+                    if matches!(mir_op, BinOp::Shl | 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 {
@@ -415,7 +415,7 @@ enum Op {
                             throw_ub_format!("overflowing shift by {} in `{}` in SIMD lane {}", r_val, intrinsic_name, i);
                         }
                     }
-                    if matches!(op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) {
+                    if matches!(mir_op, BinOp::Eq | BinOp::Ne | BinOp::Lt | BinOp::Le | BinOp::Gt | BinOp::Ge) {
                         // Special handling for boolean-returning operations
                         assert_eq!(ty, this.tcx.types.bool);
                         let val = val.to_bool().unwrap();
@@ -469,7 +469,28 @@ enum Op {
                         }
                     };
                 }
+                this.write_immediate(*res, dest)?;
+            }
+            #[rustfmt::skip]
+            | "simd_reduce_add_ordered"
+            | "simd_reduce_mul_ordered" => {
+                use mir::BinOp;
+
+                let &[ref op, ref init] = check_arg_count(args)?;
+                let (op, op_len) = this.operand_to_simd(op)?;
+                let init = this.read_immediate(init)?;
 
+                let mir_op = match intrinsic_name {
+                    "simd_reduce_add_ordered" => BinOp::Add,
+                    "simd_reduce_mul_ordered" => BinOp::Mul,
+                    _ => unreachable!(),
+                };
+
+                let mut res = init;
+                for i in 0..op_len {
+                    let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
+                    res = this.binary_op(mir_op, &res, &op)?;
+                }
                 this.write_immediate(*res, dest)?;
             }
             "simd_select" => {
index ef8a5752b7cc71f1e6042403ed0a729ebadece02..9d1ca12a9f10e041abcd87b44f5dd4bf471cd032 100644 (file)
@@ -75,6 +75,10 @@ fn simd_ops_i32() {
     assert_eq!(b.horizontal_or(), -1);
     assert_eq!(a.horizontal_xor(), 0);
     assert_eq!(b.horizontal_xor(), -4);
+    assert_eq!(a.horizontal_sum(), 40);
+    assert_eq!(b.horizontal_sum(), 2);
+    assert_eq!(a.horizontal_product(), 100*100);
+    assert_eq!(b.horizontal_product(), 6*-4);
 }
 
 fn simd_intrinsics() {