diff --git a/example/std_example.rs b/example/std_example.rs index 7fe1d082e34..8a4a6337ca7 100644 --- a/example/std_example.rs +++ b/example/std_example.rs @@ -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)] diff --git a/src/abi.rs b/src/abi.rs index 0fa546f50e5..3de9ea60e71 100644 --- a/src/abi.rs +++ b/src/abi.rs @@ -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::>() - }; - 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::>() + }; + codegen_call_inner( fx, Some(func), diff --git a/src/intrinsics.rs b/src/intrinsics.rs index 5c7f8b46f5c..c8d8bd7a793 100644 --- a/src/intrinsics.rs +++ b/src/intrinsics.rs @@ -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>, + 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, (c from) { @@ -807,8 +813,8 @@ pub fn codegen_intrinsic_call<'a, 'tcx: 'a>( }; // simd_shuffle32(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::>() + }; + + 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) { diff --git a/src/llvm_intrinsics.rs b/src/llvm_intrinsics.rs index 765adafa10b..1ffd43bb780 100644 --- a/src/llvm_intrinsics.rs +++ b/src/llvm_intrinsics.rs @@ -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>, + args: &[mir::Operand<'tcx>], destination: Option<(CPlace<'tcx>, BasicBlock)>, ) { fx.tcx.sess.warn(&format!("unsupported llvm intrinsic {}; replacing with trap", intrinsic));