pub u8: TyAndLayout<'tcx>,
pub u32: TyAndLayout<'tcx>,
pub usize: TyAndLayout<'tcx>,
+ pub bool: TyAndLayout<'tcx>,
}
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)?,
})
}
}
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")
FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
}
}
- _ => bug!(),
};
this.write_scalar(val, &dest.into())?;
}
}
}
}
- "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)?;
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() {