Skip to content

Commit c28d989

Browse files
committed
Auto merge of #115933 - oli-obk:simd_shuffle_const, r=workingjubilee
Prototype using const generic for simd_shuffle IDX array cc rust-lang/rust#85229 r? `@workingjubilee` on the design TLDR: there is now a `fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;` intrinsic that allows replacing ```rust simd_shuffle(a, b, const { stuff }) ``` with ```rust simd_shuffle_generic::<_, _, {&stuff}>(a, b) ``` which makes the compiler implementations much simpler, if we manage to at some point eliminate `simd_shuffle`. There are some issues with this today though (can't do math without bubbling it up in the generic arguments). With this change, we can start porting the simple cases and get better data on the others.
2 parents 6079cc6 + 84830cc commit c28d989

File tree

3 files changed

+56
-3
lines changed

3 files changed

+56
-3
lines changed

src/shims/intrinsics/mod.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
6060
}
6161

6262
// The rest jumps to `ret` immediately.
63-
this.emulate_intrinsic_by_name(intrinsic_name, args, dest)?;
63+
this.emulate_intrinsic_by_name(intrinsic_name, instance.args, args, dest)?;
6464

6565
trace!("{:?}", this.dump_place(dest));
6666
this.go_to_block(ret);
@@ -71,6 +71,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
7171
fn emulate_intrinsic_by_name(
7272
&mut self,
7373
intrinsic_name: &str,
74+
generic_args: ty::GenericArgsRef<'tcx>,
7475
args: &[OpTy<'tcx, Provenance>],
7576
dest: &PlaceTy<'tcx, Provenance>,
7677
) -> InterpResult<'tcx> {
@@ -80,7 +81,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
8081
return this.emulate_atomic_intrinsic(name, args, dest);
8182
}
8283
if let Some(name) = intrinsic_name.strip_prefix("simd_") {
83-
return this.emulate_simd_intrinsic(name, args, dest);
84+
return this.emulate_simd_intrinsic(name, generic_args, args, dest);
8485
}
8586

8687
match intrinsic_name {

src/shims/intrinsics/simd.rs

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
1212
fn emulate_simd_intrinsic(
1313
&mut self,
1414
intrinsic_name: &str,
15+
generic_args: ty::GenericArgsRef<'tcx>,
1516
args: &[OpTy<'tcx, Provenance>],
1617
dest: &PlaceTy<'tcx, Provenance>,
1718
) -> InterpResult<'tcx> {
@@ -488,6 +489,38 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriInterpCxExt<'mir, 'tcx> {
488489
this.write_immediate(*val, &dest)?;
489490
}
490491
}
492+
"shuffle_generic" => {
493+
let [left, right] = check_arg_count(args)?;
494+
let (left, left_len) = this.operand_to_simd(left)?;
495+
let (right, right_len) = this.operand_to_simd(right)?;
496+
let (dest, dest_len) = this.place_to_simd(dest)?;
497+
498+
let index = generic_args[2].expect_const().eval(*this.tcx, this.param_env(), Some(this.tcx.span)).unwrap().unwrap_branch();
499+
let index_len = index.len();
500+
501+
assert_eq!(left_len, right_len);
502+
assert_eq!(index_len as u64, dest_len);
503+
504+
for i in 0..dest_len {
505+
let src_index: u64 = index[i as usize].unwrap_leaf()
506+
.try_to_u32().unwrap()
507+
.into();
508+
let dest = this.project_index(&dest, i)?;
509+
510+
let val = if src_index < left_len {
511+
this.read_immediate(&this.project_index(&left, src_index)?)?
512+
} else if src_index < left_len.checked_add(right_len).unwrap() {
513+
let right_idx = src_index.checked_sub(left_len).unwrap();
514+
this.read_immediate(&this.project_index(&right, right_idx)?)?
515+
} else {
516+
span_bug!(
517+
this.cur_span(),
518+
"simd_shuffle index {src_index} is out of bounds for 2 vectors of size {left_len}",
519+
);
520+
};
521+
this.write_immediate(*val, &dest)?;
522+
}
523+
}
491524
"shuffle" => {
492525
let [left, right, index] = check_arg_count(args)?;
493526
let (left, left_len) = this.operand_to_simd(left)?;

tests/pass/portable-simd.rs

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
//@compile-flags: -Zmiri-strict-provenance
2-
#![feature(portable_simd, platform_intrinsics)]
2+
#![feature(portable_simd, platform_intrinsics, adt_const_params, inline_const)]
3+
#![allow(incomplete_features)]
34
use std::simd::*;
45

56
extern "platform-intrinsic" {
@@ -390,6 +391,8 @@ fn simd_intrinsics() {
390391
fn simd_reduce_any<T>(x: T) -> bool;
391392
fn simd_reduce_all<T>(x: T) -> bool;
392393
fn simd_select<M, T>(m: M, yes: T, no: T) -> T;
394+
fn simd_shuffle_generic<T, U, const IDX: &'static [u32]>(x: T, y: T) -> U;
395+
fn simd_shuffle<T, IDX, U>(x: T, y: T, idx: IDX) -> U;
393396
}
394397
unsafe {
395398
// Make sure simd_eq returns all-1 for `true`
@@ -413,6 +416,22 @@ fn simd_intrinsics() {
413416
simd_select(i8x4::from_array([0, -1, -1, 0]), b, a),
414417
i32x4::from_array([10, 2, 10, 10])
415418
);
419+
assert_eq!(
420+
simd_shuffle_generic::<_, i32x4, {&[3, 1, 0, 2]}>(a, b),
421+
a,
422+
);
423+
assert_eq!(
424+
simd_shuffle::<_, _, i32x4>(a, b, const {[3, 1, 0, 2]}),
425+
a,
426+
);
427+
assert_eq!(
428+
simd_shuffle_generic::<_, i32x4, {&[7, 5, 4, 6]}>(a, b),
429+
i32x4::from_array([4, 2, 1, 10]),
430+
);
431+
assert_eq!(
432+
simd_shuffle::<_, _, i32x4>(a, b, const {[7, 5, 4, 6]}),
433+
i32x4::from_array([4, 2, 1, 10]),
434+
);
416435
}
417436
}
418437

0 commit comments

Comments
 (0)