Skip to content

Commit 3eba7fc

Browse files
committed
implement simd_shuffle
1 parent 5aeff5d commit 3eba7fc

File tree

2 files changed

+52
-1
lines changed

2 files changed

+52
-1
lines changed

src/shims/intrinsics.rs

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ use std::iter;
33
use log::trace;
44

55
use rustc_apfloat::{Float, Round};
6-
use rustc_middle::ty::layout::{IntegerExt, LayoutOf};
6+
use rustc_middle::ty::layout::{HasParamEnv, IntegerExt, LayoutOf};
77
use rustc_middle::{mir, mir::BinOp, ty, ty::FloatTy};
88
use rustc_target::abi::{Align, Integer};
99

@@ -614,6 +614,45 @@ pub trait EvalContextExt<'mir, 'tcx: 'mir>: crate::MiriEvalContextExt<'mir, 'tcx
614614
this.write_immediate(val, &dest.into())?;
615615
}
616616
}
617+
"simd_shuffle" => {
618+
let &[ref left, ref right, ref index] = check_arg_count(args)?;
619+
let (left, left_len) = this.operand_to_simd(left)?;
620+
let (right, right_len) = this.operand_to_simd(right)?;
621+
let (dest, dest_len) = this.place_to_simd(dest)?;
622+
623+
// `index` is an array, not a SIMD type
624+
let ty::Array(_, index_len) = index.layout.ty.kind() else {
625+
bug!("simd_shuffle index argument has non-array type {}", index.layout.ty)
626+
};
627+
let index_len = index_len.eval_usize(*this.tcx, this.param_env());
628+
629+
assert_eq!(left_len, right_len);
630+
assert_eq!(index_len, dest_len);
631+
632+
for i in 0..dest_len {
633+
let src_index: u64 = this
634+
.read_immediate(&this.operand_index(&index, i)?.into())?
635+
.to_scalar()?
636+
.to_u32()?
637+
.into();
638+
let dest = this.mplace_index(&dest, i)?;
639+
640+
let val = if src_index < left_len {
641+
this.read_immediate(&this.mplace_index(&left, src_index)?.into())?
642+
} else if src_index < left_len.checked_add(right_len).unwrap() {
643+
this.read_immediate(
644+
&this.mplace_index(&right, src_index - left_len)?.into(),
645+
)?
646+
} else {
647+
bug!(
648+
"simd_shuffle index {} is out of bounds for 2 vectors of size {}",
649+
src_index,
650+
left_len
651+
);
652+
};
653+
this.write_immediate(*val, &dest.into())?;
654+
}
655+
}
617656

618657
// Atomic operations
619658
"atomic_load" => this.atomic_load(args, dest, AtomicReadOp::SeqCst)?,

tests/run-pass/portable-simd.rs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,17 @@ fn simd_cast() {
238238
}
239239
}
240240

241+
fn simd_swizzle() {
242+
use Which::*;
243+
244+
let a = f32x4::splat(10.0);
245+
let b = f32x4::from_array([1.0, 2.0, 3.0, -4.0]);
246+
247+
assert_eq!(simd_swizzle!(b, [3, 0, 0, 2]), f32x4::from_array([-4.0, 1.0, 1.0, 3.0]));
248+
assert_eq!(simd_swizzle!(b, [1, 2]), f32x2::from_array([2.0, 3.0]));
249+
assert_eq!(simd_swizzle!(b, a, [First(3), Second(0)]), f32x2::from_array([-4.0, 10.0]));
250+
}
251+
241252
fn simd_intrinsics() {
242253
extern "platform-intrinsic" {
243254
fn simd_eq<T, U>(x: T, y: T) -> U;
@@ -276,5 +287,6 @@ fn main() {
276287
simd_ops_f64();
277288
simd_ops_i32();
278289
simd_cast();
290+
simd_swizzle();
279291
simd_intrinsics();
280292
}

0 commit comments

Comments
 (0)