4 pub fn codegen_simd_intrinsic_call<'tcx>(
5 fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
6 instance: Instance<'tcx>,
7 args: &[mir::Operand<'tcx>],
11 let def_id = instance.def_id();
12 let substs = instance.substs;
14 let intrinsic = fx.tcx.item_name(def_id).as_str();
15 let intrinsic = &intrinsic[..];
18 fx, intrinsic, substs, args,
20 fx.tcx.sess.fatal(&format!("Unknown SIMD intrinsic {}", intrinsic));
24 let (lane_layout, lane_count) = lane_type_and_count(fx, a.layout(), intrinsic);
25 let (ret_lane_layout, ret_lane_count) = lane_type_and_count(fx, ret.layout(), intrinsic);
26 assert_eq!(lane_count, ret_lane_count);
28 let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();
30 let from_signed = type_sign(lane_layout.ty);
31 let to_signed = type_sign(ret_lane_layout.ty);
33 for lane in 0..lane_count {
34 let lane = mir::Field::new(lane.try_into().unwrap());
36 let a_lane = a.value_field(fx, lane).load_scalar(fx);
37 let res = clif_int_or_float_cast(fx, a_lane, from_signed, ret_lane_ty, to_signed);
38 ret.place_field(fx, lane).write_cvalue(fx, CValue::by_val(res, ret_lane_layout));
43 simd_cmp!(fx, intrinsic, Equal(x, y) -> ret);
46 simd_cmp!(fx, intrinsic, NotEqual(x, y) -> ret);
49 simd_cmp!(fx, intrinsic, UnsignedLessThan|SignedLessThan(x, y) -> ret);
52 simd_cmp!(fx, intrinsic, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret);
55 simd_cmp!(fx, intrinsic, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret);
58 simd_cmp!(fx, intrinsic, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret);
61 // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U
62 _ if intrinsic.starts_with("simd_shuffle"), (c x, c y, o idx) {
63 let n: u32 = intrinsic["simd_shuffle".len()..].parse().unwrap();
65 assert_eq!(x.layout(), y.layout());
66 let layout = x.layout();
68 let (lane_type, lane_count) = lane_type_and_count(fx, layout, intrinsic);
69 let (ret_lane_type, ret_lane_count) = lane_type_and_count(fx, ret.layout(), intrinsic);
71 assert_eq!(lane_type, ret_lane_type);
72 assert_eq!(n, ret_lane_count);
74 let total_len = lane_count * 2;
77 use rustc::mir::interpret::*;
78 let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
80 let idx_bytes = match idx_const.val {
81 ty::ConstKind::Value(ConstValue::ByRef { alloc, offset }) => {
82 let ptr = Pointer::new(AllocId(0 /* dummy */), offset);
83 let size = Size::from_bytes(4 * u64::from(ret_lane_count) /* size_of([u32; ret_lane_count]) */);
84 alloc.get_bytes(fx, ptr, size).unwrap()
86 _ => unreachable!("{:?}", idx_const),
89 (0..ret_lane_count).map(|i| {
90 let i = usize::try_from(i).unwrap();
91 let idx = rustc::mir::interpret::read_target_uint(
92 fx.tcx.data_layout.endian,
93 &idx_bytes[4*i.. 4*i + 4],
94 ).expect("read_target_uint");
95 u32::try_from(idx).expect("try_from u32")
96 }).collect::<Vec<u32>>()
99 for &idx in &indexes {
100 assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
103 for (out_idx, in_idx) in indexes.into_iter().enumerate() {
104 let in_lane = if in_idx < lane_count {
105 x.value_field(fx, mir::Field::new(in_idx.try_into().unwrap()))
107 y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap()))
109 let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
110 out_lane.write_cvalue(fx, in_lane);
114 simd_extract, (c v, o idx) {
115 let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) {
118 fx.tcx.sess.span_warn(
120 "`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
122 crate::trap::trap_panic(fx, "`#[rustc_arg_required_const(..)]` is not yet supported.");
126 let idx = idx_const.val.try_to_bits(Size::from_bytes(4 /* u32*/)).expect(&format!("kind not scalar: {:?}", idx_const));
127 let (_lane_type, lane_count) = lane_type_and_count(fx, v.layout(), intrinsic);
128 if idx >= lane_count.into() {
129 fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count));
132 let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
133 ret.write_cvalue(fx, ret_lane);
136 simd_add, (c x, c y) {
137 simd_int_flt_binop!(fx, intrinsic, iadd|fadd(x, y) -> ret);
139 simd_sub, (c x, c y) {
140 simd_int_flt_binop!(fx, intrinsic, isub|fsub(x, y) -> ret);
142 simd_mul, (c x, c y) {
143 simd_int_flt_binop!(fx, intrinsic, imul|fmul(x, y) -> ret);
145 simd_div, (c x, c y) {
146 simd_int_flt_binop!(fx, intrinsic, udiv|sdiv|fdiv(x, y) -> ret);
148 simd_shl, (c x, c y) {
149 simd_int_binop!(fx, intrinsic, ishl(x, y) -> ret);
151 simd_shr, (c x, c y) {
152 simd_int_binop!(fx, intrinsic, ushr|sshr(x, y) -> ret);
154 simd_and, (c x, c y) {
155 simd_int_binop!(fx, intrinsic, band(x, y) -> ret);
157 simd_or, (c x, c y) {
158 simd_int_binop!(fx, intrinsic, bor(x, y) -> ret);
160 simd_xor, (c x, c y) {
161 simd_int_binop!(fx, intrinsic, bxor(x, y) -> ret);
164 simd_fmin, (c x, c y) {
165 simd_flt_binop!(fx, intrinsic, fmin(x, y) -> ret);
167 simd_fmax, (c x, c y) {
168 simd_flt_binop!(fx, intrinsic, fmax(x, y) -> ret);