Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 76b8947

Browse files
committed
[WIP] simd_shuffle*
1 parent 78e0525 commit 76b8947

File tree

4 files changed

+98
-39
lines changed

4 files changed

+98
-39
lines changed

example/std_example.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,10 +59,12 @@ unsafe fn test_simd() {
5959
let or = _mm_or_si128(x, y);
6060
let cmp_eq = _mm_cmpeq_epi8(y, y);
6161
let cmp_lt = _mm_cmplt_epi8(y, y);
62+
let shl = _mm_slli_si128(y, 1);
6263

6364
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
6465
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
6566
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
67+
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 0]);
6668
}
6769

6870
#[derive(PartialEq)]

src/abi.rs

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -613,28 +613,6 @@ pub fn codegen_terminator_call<'a, 'tcx: 'a>(
613613
let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
614614
let sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
615615

616-
// Unpack arguments tuple for closures
617-
let args = if sig.abi == Abi::RustCall {
618-
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
619-
let self_arg = trans_operand(fx, &args[0]);
620-
let pack_arg = trans_operand(fx, &args[1]);
621-
let mut args = Vec::new();
622-
args.push(self_arg);
623-
match pack_arg.layout().ty.sty {
624-
ty::Tuple(ref tupled_arguments) => {
625-
for (i, _) in tupled_arguments.iter().enumerate() {
626-
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
627-
}
628-
}
629-
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
630-
}
631-
args
632-
} else {
633-
args.into_iter()
634-
.map(|arg| trans_operand(fx, arg))
635-
.collect::<Vec<_>>()
636-
};
637-
638616
let destination = destination
639617
.as_ref()
640618
.map(|&(ref place, bb)| (trans_place(fx, place), bb));
@@ -664,6 +642,28 @@ pub fn codegen_terminator_call<'a, 'tcx: 'a>(
664642
}
665643
}
666644

645+
// Unpack arguments tuple for closures
646+
let args = if sig.abi == Abi::RustCall {
647+
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
648+
let self_arg = trans_operand(fx, &args[0]);
649+
let pack_arg = trans_operand(fx, &args[1]);
650+
let mut args = Vec::new();
651+
args.push(self_arg);
652+
match pack_arg.layout().ty.sty {
653+
ty::Tuple(ref tupled_arguments) => {
654+
for (i, _) in tupled_arguments.iter().enumerate() {
655+
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
656+
}
657+
}
658+
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
659+
}
660+
args
661+
} else {
662+
args.into_iter()
663+
.map(|arg| trans_operand(fx, arg))
664+
.collect::<Vec<_>>()
665+
};
666+
667667
codegen_call_inner(
668668
fx,
669669
Some(func),

src/intrinsics.rs

Lines changed: 73 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,14 @@ macro_rules! intrinsic_pat {
1212
}
1313

1414
macro_rules! intrinsic_arg {
15-
(c $fx:expr, $arg:ident) => {
15+
(o $fx:expr, $arg:ident) => {
1616
$arg
1717
};
18+
(c $fx:expr, $arg:ident) => {
19+
trans_operand($fx, $arg)
20+
};
1821
(v $fx:expr, $arg:ident) => {
19-
$arg.load_scalar($fx)
22+
trans_operand($fx, $arg).load_scalar($fx)
2023
};
2124
}
2225

@@ -40,9 +43,9 @@ macro_rules! intrinsic_match {
4043
$(
4144
intrinsic_substs!($substs, 0, $($subst),*);
4245
)?
43-
if let [$($arg),*] = *$args {
44-
let ($($arg),*) = (
45-
$(intrinsic_arg!($a $fx, $arg)),*
46+
if let [$($arg),*] = $args {
47+
let ($($arg,)*) = (
48+
$(intrinsic_arg!($a $fx, $arg),)*
4649
);
4750
#[warn(unused_parens, non_snake_case)]
4851
{
@@ -67,7 +70,10 @@ macro_rules! call_intrinsic_match {
6770
$(
6871
stringify!($name) => {
6972
assert!($substs.is_noop());
70-
if let [$($arg),*] = *$args {
73+
if let [$(ref $arg),*] = *$args {
74+
let ($($arg,)*) = (
75+
$(trans_operand($fx, $arg),)*
76+
);
7177
let res = $fx.easy_call(stringify!($func), &[$($arg),*], $fx.tcx.types.$ty);
7278
$ret.write_cvalue($fx, res);
7379

@@ -120,10 +126,10 @@ fn lane_type_and_count<'tcx>(
120126
fx: &FunctionCx<'_, 'tcx, impl Backend>,
121127
layout: TyLayout<'tcx>,
122128
intrinsic: &str,
123-
) -> (TyLayout<'tcx>, usize) {
129+
) -> (TyLayout<'tcx>, u32) {
124130
assert!(layout.ty.is_simd());
125131
let lane_count = match layout.fields {
126-
layout::FieldPlacement::Array { stride: _, count } => usize::try_from(count).unwrap(),
132+
layout::FieldPlacement::Array { stride: _, count } => u32::try_from(count).unwrap(),
127133
_ => panic!("Non vector type {:?} passed to or returned from simd_* intrinsic {}", layout.ty, intrinsic),
128134
};
129135
let lane_layout = layout.field(fx, 0);
@@ -146,7 +152,7 @@ fn simd_for_each_lane<'tcx, B: Backend>(
146152
assert_eq!(lane_count, ret_lane_count);
147153

148154
for lane in 0..lane_count {
149-
let lane = mir::Field::new(lane);
155+
let lane = mir::Field::new(lane.try_into().unwrap());
150156
let x_lane = x.value_field(fx, lane).load_scalar(fx);
151157
let y_lane = y.value_field(fx, lane).load_scalar(fx);
152158

@@ -212,7 +218,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
212218
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
213219
def_id: DefId,
214220
substs: SubstsRef<'tcx>,
215-
args: Vec<CValue<'tcx>>,
221+
args: &[mir::Operand<'tcx>],
216222
destination: Option<(CPlace<'tcx>, BasicBlock)>,
217223
) {
218224
let intrinsic = fx.tcx.item_name(def_id).as_str();
@@ -499,7 +505,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
499505
let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
500506
let base_val = base.load_scalar(fx);
501507
let res = fx.bcx.ins().iadd(base_val, ptr_diff);
502-
ret.write_cvalue(fx, CValue::by_val(res, args[0].layout()));
508+
ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
503509
};
504510

505511
transmute, <src_ty, dst_ty> (c from) {
@@ -807,8 +813,8 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
807813
};
808814

809815
// simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
810-
_ if intrinsic.starts_with("simd_shuffle"), (c x, c y, c idx) {
811-
let n: usize = intrinsic["simd_shuffle".len()..].parse().unwrap();
816+
_ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
817+
let n: u32 = intrinsic["simd_shuffle".len()..].parse().unwrap();
812818

813819
assert_eq!(x.layout(), y.layout());
814820
let layout = x.layout();
@@ -821,9 +827,60 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
821827

822828
let total_len = lane_count * 2;
823829

824-
// TODO get shuffle indices
825-
fx.tcx.sess.warn("simd_shuffle* not yet implemented");
826-
crate::trap::trap_unimplemented(fx, "simd_shuffle* not yet implemented");
830+
let indexes = {
831+
use rustc::mir::interpret::*;
832+
let idx_place = match idx {
833+
Operand::Copy(idx_place) => {
834+
idx_place
835+
}
836+
_ => panic!("simd_shuffle* idx is not Operand::Copy, but {:?}", idx),
837+
};
838+
839+
assert!(idx_place.projection.is_none());
840+
let static_ = match &idx_place.base {
841+
PlaceBase::Static(static_) => {
842+
static_
843+
}
844+
PlaceBase::Local(_) => panic!("simd_shuffle* idx is not constant, but a local"),
845+
};
846+
847+
let idx_const = match &static_.kind {
848+
StaticKind::Static(_) => unimplemented!(),
849+
StaticKind::Promoted(promoted) => {
850+
fx.tcx.const_eval(ParamEnv::reveal_all().and(GlobalId {
851+
instance: fx.instance,
852+
promoted: Some(*promoted),
853+
})).unwrap()
854+
}
855+
};
856+
857+
let idx_bytes = match idx_const.val {
858+
ConstValue::ByRef { align: _, offset, alloc } => {
859+
let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
860+
let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
861+
alloc.get_bytes(fx, ptr, size).unwrap()
862+
}
863+
_ => unreachable!("{:?}", idx_const),
864+
};
865+
866+
(0..ret_lane_count).map(|i| {
867+
let i = usize::try_from(i).unwrap();
868+
let idx = rustc::mir::interpret::read_target_uint(
869+
fx.tcx.data_layout.endian,
870+
&idx_bytes[4*i.. 4*i + 4],
871+
).expect("read_target_uint");
872+
u32::try_from(idx).expect("try_from u32")
873+
}).collect::<Vec<u32>>()
874+
};
875+
876+
for &idx in &indexes {
877+
assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
878+
}
879+
880+
881+
882+
println!("{:?}", indexes);
883+
unimplemented!();
827884
};
828885

829886
simd_add, (c x, c y) {

src/llvm_intrinsics.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ pub fn codegen_llvm_intrinsic_call<'a, 'tcx: 'a>(
66
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
77
intrinsic: &str,
88
substs: SubstsRef<'tcx>,
9-
args: Vec<CValue<'tcx>>,
9+
args: &[mir::Operand<'tcx>],
1010
destination: Option<(CPlace<'tcx>, BasicBlock)>,
1111
) {
1212
fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));

0 commit comments

Comments
 (0)