Skip to content

Commit 3ed8ad4

Browse files
committed
avoid repeated string matching, and add more simd_reduce intrinsics
1 parent 3854a76 commit 3ed8ad4

File tree

3 files changed

+55
-16
lines changed

3 files changed

+55
-16
lines changed

src/machine.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -267,6 +267,7 @@ pub struct PrimitiveLayouts<'tcx> {
267267
pub u8: TyAndLayout<'tcx>,
268268
pub u32: TyAndLayout<'tcx>,
269269
pub usize: TyAndLayout<'tcx>,
270+
pub bool: TyAndLayout<'tcx>,
270271
}
271272

272273
impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
@@ -279,6 +280,7 @@ impl<'mir, 'tcx: 'mir> PrimitiveLayouts<'tcx> {
279280
u8: layout_cx.layout_of(layout_cx.tcx.types.u8)?,
280281
u32: layout_cx.layout_of(layout_cx.tcx.types.u32)?,
281282
usize: layout_cx.layout_of(layout_cx.tcx.types.usize)?,
283+
bool: layout_cx.layout_of(layout_cx.tcx.types.bool)?,
282284
})
283285
}
284286
}

src/shims/intrinsics.rs

Lines changed: 46 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -324,12 +324,22 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
324324

325325
assert_eq!(dest_len, op_len);
326326

327+
enum Op {
328+
MirOp(mir::UnOp),
329+
Abs,
330+
}
331+
let which = match intrinsic_name {
332+
"simd_neg" => Op::MirOp(mir::UnOp::Neg),
333+
"simd_fabs" => Op::Abs,
334+
_ => unreachable!(),
335+
};
336+
327337
for i in 0..dest_len {
328338
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
329339
let dest = this.mplace_index(&dest, i)?;
330-
let val = match intrinsic_name {
331-
"simd_neg" => this.unary_op(mir::UnOp::Neg, &op)?.to_scalar()?,
332-
"simd_fabs" => {
340+
let val = match which {
341+
Op::MirOp(mir_op) => this.unary_op(mir_op, &op)?.to_scalar()?,
342+
Op::Abs => {
333343
// Works for f32 and f64.
334344
let ty::Float(float_ty) = op.layout.ty.kind() else {
335345
bug!("simd_fabs operand is not a float")
@@ -341,7 +351,6 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
341351
FloatTy::F64 => Scalar::from_f64(op.to_f64()?.abs()),
342352
}
343353
}
344-
_ => bug!(),
345354
};
346355
this.write_scalar(val, &dest.into())?;
347356
}
@@ -419,28 +428,49 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
419428
}
420429
}
421430
}
422-
"simd_reduce_any" | "simd_reduce_all" => {
431+
#[rustfmt::skip]
432+
| "simd_reduce_and"
433+
| "simd_reduce_or"
434+
| "simd_reduce_xor"
435+
| "simd_reduce_any"
436+
| "simd_reduce_all" => {
437+
use mir::BinOp;
438+
423439
let &[ref op] = check_arg_count(args)?;
424440
let (op, op_len) = this.operand_to_simd(op)?;
425441

426-
// the neutral element
427-
let mut res = match intrinsic_name {
428-
"simd_reduce_any" => false,
429-
"simd_reduce_all" => true,
430-
_ => bug!(),
442+
let imm_from_bool =
443+
|b| ImmTy::from_scalar(Scalar::from_bool(b), this.machine.layouts.bool);
444+
445+
enum Op {
446+
MirOp(BinOp),
447+
MirOpBool(BinOp),
448+
}
449+
// The initial value is the neutral element.
450+
let (which, init) = match intrinsic_name {
451+
"simd_reduce_and" => (Op::MirOp(BinOp::BitAnd), ImmTy::from_int(-1, dest.layout)),
452+
"simd_reduce_or" => (Op::MirOp(BinOp::BitOr), ImmTy::from_int(0, dest.layout)),
453+
"simd_reduce_xor" => (Op::MirOp(BinOp::BitXor), ImmTy::from_int(0, dest.layout)),
454+
"simd_reduce_any" => (Op::MirOpBool(BinOp::BitOr), imm_from_bool(false)),
455+
"simd_reduce_all" => (Op::MirOpBool(BinOp::BitAnd), imm_from_bool(true)),
456+
_ => unreachable!(),
431457
};
432458

459+
let mut res = init;
433460
for i in 0..op_len {
434461
let op = this.read_immediate(&this.mplace_index(&op, i)?.into())?;
435-
let val = simd_element_to_bool(op)?;
436-
res = match intrinsic_name {
437-
"simd_reduce_any" => res | val,
438-
"simd_reduce_all" => res & val,
439-
_ => bug!(),
462+
res = match which {
463+
Op::MirOp(mir_op) => {
464+
this.binary_op(mir_op, &res, &op)?
465+
}
466+
Op::MirOpBool(mir_op) => {
467+
let op = imm_from_bool(simd_element_to_bool(op)?);
468+
this.binary_op(mir_op, &res, &op)?
469+
}
440470
};
441471
}
442472

443-
this.write_scalar(Scalar::from_bool(res), dest)?;
473+
this.write_immediate(*res, dest)?;
444474
}
445475
"simd_select" => {
446476
let &[ref mask, ref yes, ref no] = check_arg_count(args)?;

tests/run-pass/portable-simd.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,13 @@ fn simd_ops_i32() {
6868
assert_eq!(a.lanes_lt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([0, 0, -1, 0])));
6969
assert_eq!(a.lanes_ge(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, -1, 0, -1])));
7070
assert_eq!(a.lanes_gt(i32x4::splat(5)*b), Mask::from_int(i32x4::from_array([-1, 0, 0, -1])));
71+
72+
assert_eq!(a.horizontal_and(), 10);
73+
assert_eq!(b.horizontal_and(), 0);
74+
assert_eq!(a.horizontal_or(), 10);
75+
assert_eq!(b.horizontal_or(), -1);
76+
assert_eq!(a.horizontal_xor(), 0);
77+
assert_eq!(b.horizontal_xor(), -4);
7178
}
7279

7380
fn simd_intrinsics() {

0 commit comments

Comments
 (0)