]> git.lizzy.rs Git - rust.git/blob - src/intrinsics/simd.rs
Move simd intrinsics to intrinsics/simd.rs
[rust.git] / src / intrinsics / simd.rs
1 use crate::prelude::*;
2 use super::*;
3
4 pub fn codegen_simd_intrinsic_call<'tcx>(
5     fx: &mut FunctionCx<'_, 'tcx, impl Backend>,
6     instance: Instance<'tcx>,
7     args: &[mir::Operand<'tcx>],
8     ret: CPlace<'tcx>,
9     span: Span,
10 ) {
11     let def_id = instance.def_id();
12     let substs = instance.substs;
13
14     let intrinsic = fx.tcx.item_name(def_id).as_str();
15     let intrinsic = &intrinsic[..];
16
17     intrinsic_match! {
18         fx, intrinsic, substs, args,
19         _ => {
20             fx.tcx.sess.fatal(&format!("Unknown SIMD intrinsic {}", intrinsic));
21         };
22
23         simd_cast, (c a) {
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);
27
28             let ret_lane_ty = fx.clif_type(ret_lane_layout.ty).unwrap();
29
30             let from_signed = type_sign(lane_layout.ty);
31             let to_signed = type_sign(ret_lane_layout.ty);
32
33             for lane in 0..lane_count {
34                 let lane = mir::Field::new(lane.try_into().unwrap());
35
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));
39             }
40         };
41
42         simd_eq, (c x, c y) {
43             simd_cmp!(fx, intrinsic, Equal(x, y) -> ret);
44         };
45         simd_ne, (c x, c y) {
46             simd_cmp!(fx, intrinsic, NotEqual(x, y) -> ret);
47         };
48         simd_lt, (c x, c y) {
49             simd_cmp!(fx, intrinsic, UnsignedLessThan|SignedLessThan(x, y) -> ret);
50         };
51         simd_le, (c x, c y) {
52             simd_cmp!(fx, intrinsic, UnsignedLessThanOrEqual|SignedLessThanOrEqual(x, y) -> ret);
53         };
54         simd_gt, (c x, c y) {
55             simd_cmp!(fx, intrinsic, UnsignedGreaterThan|SignedGreaterThan(x, y) -> ret);
56         };
57         simd_ge, (c x, c y) {
58             simd_cmp!(fx, intrinsic, UnsignedGreaterThanOrEqual|SignedGreaterThanOrEqual(x, y) -> ret);
59         };
60
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();
64
65             assert_eq!(x.layout(), y.layout());
66             let layout = x.layout();
67
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);
70
71             assert_eq!(lane_type, ret_lane_type);
72             assert_eq!(n, ret_lane_count);
73
74             let total_len = lane_count * 2;
75
76             let indexes = {
77                 use rustc::mir::interpret::*;
78                 let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const");
79
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()
85                     }
86                     _ => unreachable!("{:?}", idx_const),
87                 };
88
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>>()
97             };
98
99             for &idx in &indexes {
100                 assert!(idx < total_len, "idx {} out of range 0..{}", idx, total_len);
101             }
102
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()))
106                 } else {
107                     y.value_field(fx, mir::Field::new((in_idx - lane_count).try_into().unwrap()))
108                 };
109                 let out_lane = ret.place_field(fx, mir::Field::new(out_idx));
110                 out_lane.write_cvalue(fx, in_lane);
111             }
112         };
113
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) {
116                 idx_const
117             } else {
118                 fx.tcx.sess.span_warn(
119                     fx.mir.span,
120                     "`#[rustc_arg_required_const(..)]` is not yet supported. Calling this function will panic.",
121                 );
122                 crate::trap::trap_panic(fx, "`#[rustc_arg_required_const(..)]` is not yet supported.");
123                 return;
124             };
125
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));
130             }
131
132             let ret_lane = v.value_field(fx, mir::Field::new(idx.try_into().unwrap()));
133             ret.write_cvalue(fx, ret_lane);
134         };
135
136         simd_add, (c x, c y) {
137             simd_int_flt_binop!(fx, intrinsic, iadd|fadd(x, y) -> ret);
138         };
139         simd_sub, (c x, c y) {
140             simd_int_flt_binop!(fx, intrinsic, isub|fsub(x, y) -> ret);
141         };
142         simd_mul, (c x, c y) {
143             simd_int_flt_binop!(fx, intrinsic, imul|fmul(x, y) -> ret);
144         };
145         simd_div, (c x, c y) {
146             simd_int_flt_binop!(fx, intrinsic, udiv|sdiv|fdiv(x, y) -> ret);
147         };
148         simd_shl, (c x, c y) {
149             simd_int_binop!(fx, intrinsic, ishl(x, y) -> ret);
150         };
151         simd_shr, (c x, c y) {
152             simd_int_binop!(fx, intrinsic, ushr|sshr(x, y) -> ret);
153         };
154         simd_and, (c x, c y) {
155             simd_int_binop!(fx, intrinsic, band(x, y) -> ret);
156         };
157         simd_or, (c x, c y) {
158             simd_int_binop!(fx, intrinsic, bor(x, y) -> ret);
159         };
160         simd_xor, (c x, c y) {
161             simd_int_binop!(fx, intrinsic, bxor(x, y) -> ret);
162         };
163
164         simd_fmin, (c x, c y) {
165             simd_flt_binop!(fx, intrinsic, fmin(x, y) -> ret);
166         };
167         simd_fmax, (c x, c y) {
168             simd_flt_binop!(fx, intrinsic, fmax(x, y) -> ret);
169         };
170     }
171 }