[WIP] simd_shuffle*

This commit is contained in:
bjorn3 2019-07-28 11:24:33 +02:00
parent 78e0525366
commit 76b89476c3
4 changed files with 98 additions and 39 deletions

View File

@ -59,10 +59,12 @@ unsafe fn test_simd() {
let or = _mm_or_si128(x, y);
let cmp_eq = _mm_cmpeq_epi8(y, y);
let cmp_lt = _mm_cmplt_epi8(y, y);
let shl = _mm_slli_si128(y, 1);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 7]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_eq), [0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(cmp_lt), [0, 0, 0, 0, 0, 0, 0, 0]);
assert_eq!(std::mem::transmute::<_, [u16; 8]>(or), [7, 7, 7, 7, 7, 7, 7, 0]);
}
#[derive(PartialEq)]

View File

@ -613,28 +613,6 @@ pub fn codegen_terminator_call<'a, 'tcx: 'a>(
let fn_ty = fx.monomorphize(&func.ty(fx.mir, fx.tcx));
let sig = fx.tcx.normalize_erasing_late_bound_regions(ParamEnv::reveal_all(), &fn_ty.fn_sig(fx.tcx));
// Unpack arguments tuple for closures
let args = if sig.abi == Abi::RustCall {
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
let self_arg = trans_operand(fx, &args[0]);
let pack_arg = trans_operand(fx, &args[1]);
let mut args = Vec::new();
args.push(self_arg);
match pack_arg.layout().ty.sty {
ty::Tuple(ref tupled_arguments) => {
for (i, _) in tupled_arguments.iter().enumerate() {
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
}
}
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
}
args
} else {
args.into_iter()
.map(|arg| trans_operand(fx, arg))
.collect::<Vec<_>>()
};
let destination = destination
.as_ref()
.map(|&(ref place, bb)| (trans_place(fx, place), bb));
@ -664,6 +642,28 @@ pub fn codegen_terminator_call<'a, 'tcx: 'a>(
}
}
// Unpack arguments tuple for closures
let args = if sig.abi == Abi::RustCall {
assert_eq!(args.len(), 2, "rust-call abi requires two arguments");
let self_arg = trans_operand(fx, &args[0]);
let pack_arg = trans_operand(fx, &args[1]);
let mut args = Vec::new();
args.push(self_arg);
match pack_arg.layout().ty.sty {
ty::Tuple(ref tupled_arguments) => {
for (i, _) in tupled_arguments.iter().enumerate() {
args.push(pack_arg.value_field(fx, mir::Field::new(i)));
}
}
_ => bug!("argument to function with \"rust-call\" ABI is not a tuple"),
}
args
} else {
args.into_iter()
.map(|arg| trans_operand(fx, arg))
.collect::<Vec<_>>()
};
codegen_call_inner(
fx,
Some(func),

View File

@ -12,11 +12,14 @@ macro_rules! intrinsic_pat {
}
macro_rules! intrinsic_arg {
(c $fx:expr, $arg:ident) => {
(o $fx:expr, $arg:ident) => {
$arg
};
(c $fx:expr, $arg:ident) => {
trans_operand($fx, $arg)
};
(v $fx:expr, $arg:ident) => {
$arg.load_scalar($fx)
trans_operand($fx, $arg).load_scalar($fx)
};
}
@ -40,9 +43,9 @@ macro_rules! intrinsic_match {
$(
intrinsic_substs!($substs, 0, $($subst),*);
)?
if let [$($arg),*] = *$args {
let ($($arg),*) = (
$(intrinsic_arg!($a $fx, $arg)),*
if let [$($arg),*] = $args {
let ($($arg,)*) = (
$(intrinsic_arg!($a $fx, $arg),)*
);
#[warn(unused_parens, non_snake_case)]
{
@ -67,7 +70,10 @@ macro_rules! call_intrinsic_match {
$(
stringify!($name) => {
assert!($substs.is_noop());
if let [$($arg),*] = *$args {
if let [$(ref $arg),*] = *$args {
let ($($arg,)*) = (
$(trans_operand($fx, $arg),)*
);
let res = $fx.easy_call(stringify!($func), &[$($arg),*], $fx.tcx.types.$ty);
$ret.write_cvalue($fx, res);
@ -120,10 +126,10 @@ fn lane_type_and_count<'tcx>(
fx: &FunctionCx<'_, 'tcx, impl Backend>,
layout: TyLayout<'tcx>,
intrinsic: &str,
) -> (TyLayout<'tcx>, usize) {
) -> (TyLayout<'tcx>, u32) {
assert!(layout.ty.is_simd());
let lane_count = match layout.fields {
layout::FieldPlacement::Array { stride: _, count } => usize::try_from(count).unwrap(),
layout::FieldPlacement::Array { stride: _, count } => u32::try_from(count).unwrap(),
_ => panic!("Non vector type {:?} passed to or returned from simd_* intrinsic {}", layout.ty, intrinsic),
};
let lane_layout = layout.field(fx, 0);
@ -146,7 +152,7 @@ fn simd_for_each_lane<'tcx, B: Backend>(
assert_eq!(lane_count, ret_lane_count);
for lane in 0..lane_count {
let lane = mir::Field::new(lane);
let lane = mir::Field::new(lane.try_into().unwrap());
let x_lane = x.value_field(fx, lane).load_scalar(fx);
let y_lane = y.value_field(fx, lane).load_scalar(fx);
@ -212,7 +218,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
def_id: DefId,
substs: SubstsRef<'tcx>,
args: Vec<CValue<'tcx>>,
args: &[mir::Operand<'tcx>],
destination: Option<(CPlace<'tcx>, BasicBlock)>,
) {
let intrinsic = fx.tcx.item_name(def_id).as_str();
@ -499,7 +505,7 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
let ptr_diff = fx.bcx.ins().imul_imm(offset, pointee_size as i64);
let base_val = base.load_scalar(fx);
let res = fx.bcx.ins().iadd(base_val, ptr_diff);
ret.write_cvalue(fx, CValue::by_val(res, args[0].layout()));
ret.write_cvalue(fx, CValue::by_val(res, base.layout()));
};
transmute, <src_ty, dst_ty> (c from) {
@ -807,8 +813,8 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
};
// simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
_ if intrinsic.starts_with("simd_shuffle"), (c x, c y, c idx) {
let n: usize = intrinsic["simd_shuffle".len()..].parse().unwrap();
_ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
let n: u32 = intrinsic["simd_shuffle".len()..].parse().unwrap();
assert_eq!(x.layout(), y.layout());
let layout = x.layout();
@ -821,9 +827,60 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>(
let total_len = lane_count * 2;
// TODO get shuffle indices
fx.tcx.sess.warn("simd_shuffle* not yet implemented");
crate::trap::trap_unimplemented(fx, "simd_shuffle* not yet implemented");
let indexes = {
use rustc::mir::interpret::*;
let idx_place = match idx {
Operand::Copy(idx_place) => {
idx_place
}
_ => panic!("simd_shuffle* idx is not Operand::Copy, but {:?}", idx),
};
assert!(idx_place.projection.is_none());
let static_ = match &idx_place.base {
PlaceBase::Static(static_) => {
static_
}
PlaceBase::Local(_) => panic!("simd_shuffle* idx is not constant, but a local"),
};
let idx_const = match &static_.kind {
StaticKind::Static(_) => unimplemented!(),
StaticKind::Promoted(promoted) => {
fx.tcx.const_eval(ParamEnv::reveal_all().and(GlobalId {
instance: fx.instance,
promoted: Some(*promoted),
})).unwrap()
}
};
let idx_bytes = match idx_const.val {
ConstValue::ByRef { align: _, offset, alloc } => {
let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
alloc.get_bytes(fx, ptr, size).unwrap()
}
_ => unreachable!("{:?}", idx_const),
};
(0..ret_lane_count).map(|i| {
let i = usize::try_from(i).unwrap();
let idx = rustc::mir::interpret::read_target_uint(
fx.tcx.data_layout.endian,
&idx_bytes[4*i.. 4*i + 4],
).expect("read_target_uint");
u32::try_from(idx).expect("try_from u32")
}).collect::<Vec<u32>>()
};
for &idx in &indexes {
assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
}
println!("{:?}", indexes);
unimplemented!();
};
simd_add, (c x, c y) {

View File

@ -6,7 +6,7 @@ pub fn codegen_llvm_intrinsic_call<'a, 'tcx: 'a>(
fx: &mut FunctionCx<'a, 'tcx, impl Backend>,
intrinsic: &str,
substs: SubstsRef<'tcx>,
args: Vec<CValue<'tcx>>,
args: &[mir::Operand<'tcx>],
destination: Option<(CPlace<'tcx>, BasicBlock)>,
) {
fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));