| "simd_reduce_or"
| "simd_reduce_xor"
| "simd_reduce_any"
- | "simd_reduce_all" => {
+ | "simd_reduce_all"
+ | "simd_reduce_max"
+ | "simd_reduce_min" => {
use mir::BinOp;
let &[ref op] = check_arg_count(args)?;
enum Op {
MirOp(BinOp),
MirOpBool(BinOp),
+ Max,
+ Min,
}
- // 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)),
+ let which = match intrinsic_name {
+ "simd_reduce_and" => Op::MirOp(BinOp::BitAnd),
+ "simd_reduce_or" => Op::MirOp(BinOp::BitOr),
+ "simd_reduce_xor" => Op::MirOp(BinOp::BitXor),
+ "simd_reduce_any" => Op::MirOpBool(BinOp::BitOr),
+ "simd_reduce_all" => Op::MirOpBool(BinOp::BitAnd),
+ "simd_reduce_max" => Op::Max,
+ "simd_reduce_min" => Op::Min,
_ => unreachable!(),
};
- let mut res = init;
- for i in 0..op_len {
+ // Initialize with first lane, then proceed with the rest.
+ let mut res = this.read_immediate(&this.mplace_index(&op, 0)?.into())?;
+ if matches!(which, Op::MirOpBool(_)) {
+ // Convert to `bool` scalar.
+ res = imm_from_bool(simd_element_to_bool(res)?);
+ }
+ for i in 1..op_len {
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
res = match which {
Op::MirOp(mir_op) => {
let op = imm_from_bool(simd_element_to_bool(op)?);
this.binary_op(mir_op, &res, &op)?
}
+ Op::Max => {
+ // if `op > res`...
+ if this.binary_op(BinOp::Gt, &op, &res)?.to_scalar()?.to_bool()? {
+ // update accumulator
+ op
+ } else {
+ // no change
+ res
+ }
+ }
+ Op::Min => {
+ // if `op < res`...
+ if this.binary_op(BinOp::Lt, &op, &res)?.to_scalar()?.to_bool()? {
+ // update accumulator
+ op
+ } else {
+ // no change
+ res
+ }
+ }
};
}
this.write_immediate(*res, dest)?;
assert_eq!(b.horizontal_sum(), 2.0);
assert_eq!(a.horizontal_product(), 100.0 * 100.0);
assert_eq!(b.horizontal_product(), -24.0);
+ assert_eq!(a.horizontal_max(), 10.0);
+ assert_eq!(b.horizontal_max(), 3.0);
+ assert_eq!(a.horizontal_min(), 10.0);
+ assert_eq!(b.horizontal_min(), -4.0);
}
fn simd_ops_f64() {
assert_eq!(b.horizontal_sum(), 2.0);
assert_eq!(a.horizontal_product(), 100.0 * 100.0);
assert_eq!(b.horizontal_product(), -24.0);
+ assert_eq!(a.horizontal_max(), 10.0);
+ assert_eq!(b.horizontal_max(), 3.0);
+ assert_eq!(a.horizontal_min(), 10.0);
+ assert_eq!(b.horizontal_min(), -4.0);
}
fn simd_ops_i32() {
assert_eq!(b.horizontal_sum(), 2);
assert_eq!(a.horizontal_product(), 100 * 100);
assert_eq!(b.horizontal_product(), -24);
+ assert_eq!(a.horizontal_max(), 10);
+ assert_eq!(b.horizontal_max(), 3);
+ assert_eq!(a.horizontal_min(), 10);
+ assert_eq!(b.horizontal_min(), -4);
}
fn simd_mask() {