avoid repeated string matching, and add more simd_reduce intrinsics
This commit is contained in:
parent
3854a76ace
commit
3ed8ad4423
@ -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)?,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
@ -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)?;
|
||||
|
@ -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() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user