]>
Commit | Line | Data |
---|---|---|
29967ef6 XL |
1 | //! Codegen `extern "platform-intrinsic"` intrinsics. |
2 | ||
5e7ed085 FG |
3 | use rustc_middle::ty::subst::SubstsRef; |
4 | use rustc_span::Symbol; | |
5 | ||
29967ef6 XL |
6 | use super::*; |
7 | use crate::prelude::*; | |
8 | ||
5e7ed085 FG |
9 | fn report_simd_type_validation_error( |
10 | fx: &mut FunctionCx<'_, '_, '_>, | |
11 | intrinsic: Symbol, | |
12 | span: Span, | |
13 | ty: Ty<'_>, | |
14 | ) { | |
15 | fx.tcx.sess.span_err(span, &format!("invalid monomorphization of `{}` intrinsic: expected SIMD input type, found non-SIMD `{}`", intrinsic, ty)); | |
16 | // Prevent verifier error | |
17 | crate::trap::trap_unreachable(fx, "compilation should not have succeeded"); | |
18 | } | |
19 | ||
29967ef6 | 20 | pub(super) fn codegen_simd_intrinsic_call<'tcx>( |
6a06907d | 21 | fx: &mut FunctionCx<'_, '_, 'tcx>, |
5e7ed085 FG |
22 | intrinsic: Symbol, |
23 | _substs: SubstsRef<'tcx>, | |
29967ef6 XL |
24 | args: &[mir::Operand<'tcx>], |
25 | ret: CPlace<'tcx>, | |
26 | span: Span, | |
27 | ) { | |
29967ef6 | 28 | intrinsic_match! { |
5e7ed085 | 29 | fx, intrinsic, args, |
29967ef6 XL |
30 | _ => { |
31 | fx.tcx.sess.span_fatal(span, &format!("Unknown SIMD intrinsic {}", intrinsic)); | |
32 | }; | |
33 | ||
34 | simd_cast, (c a) { | |
5e7ed085 FG |
35 | if !a.layout().ty.is_simd() { |
36 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
37 | return; | |
38 | } | |
39 | ||
40 | simd_for_each_lane(fx, a, ret, &|fx, lane_ty, ret_lane_ty, lane| { | |
41 | let ret_lane_clif_ty = fx.clif_type(ret_lane_ty).unwrap(); | |
29967ef6 | 42 | |
5e7ed085 FG |
43 | let from_signed = type_sign(lane_ty); |
44 | let to_signed = type_sign(ret_lane_ty); | |
29967ef6 | 45 | |
5e7ed085 | 46 | clif_int_or_float_cast(fx, lane, from_signed, ret_lane_clif_ty, to_signed) |
29967ef6 XL |
47 | }); |
48 | }; | |
49 | ||
5e7ed085 FG |
50 | simd_eq | simd_ne | simd_lt | simd_le | simd_gt | simd_ge, (c x, c y) { |
51 | if !x.layout().ty.is_simd() { | |
52 | report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); | |
53 | return; | |
54 | } | |
55 | ||
56 | // FIXME use vector instructions when possible | |
57 | simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, res_lane_ty, x_lane, y_lane| { | |
58 | let res_lane = match (lane_ty.kind(), intrinsic) { | |
59 | (ty::Uint(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane), | |
60 | (ty::Uint(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane), | |
61 | (ty::Uint(_), sym::simd_lt) => { | |
62 | fx.bcx.ins().icmp(IntCC::UnsignedLessThan, x_lane, y_lane) | |
63 | } | |
64 | (ty::Uint(_), sym::simd_le) => { | |
65 | fx.bcx.ins().icmp(IntCC::UnsignedLessThanOrEqual, x_lane, y_lane) | |
66 | } | |
67 | (ty::Uint(_), sym::simd_gt) => { | |
68 | fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, x_lane, y_lane) | |
69 | } | |
70 | (ty::Uint(_), sym::simd_ge) => { | |
71 | fx.bcx.ins().icmp(IntCC::UnsignedGreaterThanOrEqual, x_lane, y_lane) | |
72 | } | |
73 | ||
74 | (ty::Int(_), sym::simd_eq) => fx.bcx.ins().icmp(IntCC::Equal, x_lane, y_lane), | |
75 | (ty::Int(_), sym::simd_ne) => fx.bcx.ins().icmp(IntCC::NotEqual, x_lane, y_lane), | |
76 | (ty::Int(_), sym::simd_lt) => fx.bcx.ins().icmp(IntCC::SignedLessThan, x_lane, y_lane), | |
77 | (ty::Int(_), sym::simd_le) => { | |
78 | fx.bcx.ins().icmp(IntCC::SignedLessThanOrEqual, x_lane, y_lane) | |
79 | } | |
80 | (ty::Int(_), sym::simd_gt) => { | |
81 | fx.bcx.ins().icmp(IntCC::SignedGreaterThan, x_lane, y_lane) | |
82 | } | |
83 | (ty::Int(_), sym::simd_ge) => { | |
84 | fx.bcx.ins().icmp(IntCC::SignedGreaterThanOrEqual, x_lane, y_lane) | |
85 | } | |
86 | ||
87 | (ty::Float(_), sym::simd_eq) => fx.bcx.ins().fcmp(FloatCC::Equal, x_lane, y_lane), | |
88 | (ty::Float(_), sym::simd_ne) => fx.bcx.ins().fcmp(FloatCC::NotEqual, x_lane, y_lane), | |
89 | (ty::Float(_), sym::simd_lt) => fx.bcx.ins().fcmp(FloatCC::LessThan, x_lane, y_lane), | |
90 | (ty::Float(_), sym::simd_le) => { | |
91 | fx.bcx.ins().fcmp(FloatCC::LessThanOrEqual, x_lane, y_lane) | |
92 | } | |
93 | (ty::Float(_), sym::simd_gt) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, x_lane, y_lane), | |
94 | (ty::Float(_), sym::simd_ge) => { | |
95 | fx.bcx.ins().fcmp(FloatCC::GreaterThanOrEqual, x_lane, y_lane) | |
96 | } | |
97 | ||
98 | _ => unreachable!(), | |
99 | }; | |
100 | ||
101 | let ty = fx.clif_type(res_lane_ty).unwrap(); | |
102 | ||
103 | let res_lane = fx.bcx.ins().bint(ty, res_lane); | |
104 | fx.bcx.ins().ineg(res_lane) | |
105 | }); | |
29967ef6 XL |
106 | }; |
107 | ||
108 | // simd_shuffle32<T, U>(x: T, y: T, idx: [u32; 32]) -> U | |
17df50a5 | 109 | _ if intrinsic.as_str().starts_with("simd_shuffle"), (c x, c y, o idx) { |
5e7ed085 FG |
110 | if !x.layout().ty.is_simd() { |
111 | report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); | |
112 | return; | |
113 | } | |
29967ef6 | 114 | |
a2a8927a XL |
115 | // If this intrinsic is the older "simd_shuffleN" form, simply parse the integer. |
116 | // If there is no suffix, use the index array length. | |
117 | let n: u16 = if intrinsic == sym::simd_shuffle { | |
118 | // Make sure this is actually an array, since typeck only checks the length-suffixed | |
119 | // version of this intrinsic. | |
120 | let idx_ty = fx.monomorphize(idx.ty(fx.mir, fx.tcx)); | |
121 | match idx_ty.kind() { | |
122 | ty::Array(ty, len) if matches!(ty.kind(), ty::Uint(ty::UintTy::U32)) => { | |
123 | len.try_eval_usize(fx.tcx, ty::ParamEnv::reveal_all()).unwrap_or_else(|| { | |
124 | span_bug!(span, "could not evaluate shuffle index array length") | |
125 | }).try_into().unwrap() | |
126 | } | |
127 | _ => { | |
128 | fx.tcx.sess.span_err( | |
129 | span, | |
130 | &format!( | |
131 | "simd_shuffle index must be an array of `u32`, got `{}`", | |
132 | idx_ty, | |
133 | ), | |
134 | ); | |
135 | // Prevent verifier error | |
136 | crate::trap::trap_unreachable(fx, "compilation should not have succeeded"); | |
137 | return; | |
138 | } | |
139 | } | |
140 | } else { | |
141 | intrinsic.as_str()["simd_shuffle".len()..].parse().unwrap() | |
142 | }; | |
29967ef6 XL |
143 | |
144 | assert_eq!(x.layout(), y.layout()); | |
145 | let layout = x.layout(); | |
146 | ||
5869c6ff XL |
147 | let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); |
148 | let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); | |
29967ef6 | 149 | |
5869c6ff XL |
150 | assert_eq!(lane_ty, ret_lane_ty); |
151 | assert_eq!(u64::from(n), ret_lane_count); | |
29967ef6 XL |
152 | |
153 | let total_len = lane_count * 2; | |
154 | ||
155 | let indexes = { | |
156 | use rustc_middle::mir::interpret::*; | |
157 | let idx_const = crate::constant::mir_operand_get_const_val(fx, idx).expect("simd_shuffle* idx not const"); | |
158 | ||
6a06907d XL |
159 | let idx_bytes = match idx_const { |
160 | ConstValue::ByRef { alloc, offset } => { | |
cdc7bbd5 | 161 | let size = Size::from_bytes(4 * ret_lane_count /* size_of([u32; ret_lane_count]) */); |
5e7ed085 | 162 | alloc.inner().get_bytes(fx, alloc_range(offset, size)).unwrap() |
29967ef6 XL |
163 | } |
164 | _ => unreachable!("{:?}", idx_const), | |
165 | }; | |
166 | ||
167 | (0..ret_lane_count).map(|i| { | |
168 | let i = usize::try_from(i).unwrap(); | |
169 | let idx = rustc_middle::mir::interpret::read_target_uint( | |
170 | fx.tcx.data_layout.endian, | |
171 | &idx_bytes[4*i.. 4*i + 4], | |
172 | ).expect("read_target_uint"); | |
173 | u16::try_from(idx).expect("try_from u32") | |
174 | }).collect::<Vec<u16>>() | |
175 | }; | |
176 | ||
177 | for &idx in &indexes { | |
5869c6ff | 178 | assert!(u64::from(idx) < total_len, "idx {} out of range 0..{}", idx, total_len); |
29967ef6 XL |
179 | } |
180 | ||
181 | for (out_idx, in_idx) in indexes.into_iter().enumerate() { | |
5869c6ff | 182 | let in_lane = if u64::from(in_idx) < lane_count { |
94222f64 | 183 | x.value_lane(fx, in_idx.into()) |
29967ef6 | 184 | } else { |
94222f64 | 185 | y.value_lane(fx, u64::from(in_idx) - lane_count) |
29967ef6 | 186 | }; |
94222f64 | 187 | let out_lane = ret.place_lane(fx, u64::try_from(out_idx).unwrap()); |
29967ef6 XL |
188 | out_lane.write_cvalue(fx, in_lane); |
189 | } | |
190 | }; | |
191 | ||
192 | simd_insert, (c base, o idx, c val) { | |
193 | // FIXME validate | |
194 | let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { | |
195 | idx_const | |
196 | } else { | |
197 | fx.tcx.sess.span_fatal( | |
198 | span, | |
199 | "Index argument for `simd_insert` is not a constant", | |
200 | ); | |
201 | }; | |
202 | ||
6a06907d | 203 | let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); |
5869c6ff | 204 | let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); |
29967ef6 XL |
205 | if idx >= lane_count.into() { |
206 | fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count)); | |
207 | } | |
208 | ||
209 | ret.write_cvalue(fx, base); | |
210 | let ret_lane = ret.place_field(fx, mir::Field::new(idx.try_into().unwrap())); | |
211 | ret_lane.write_cvalue(fx, val); | |
212 | }; | |
213 | ||
214 | simd_extract, (c v, o idx) { | |
5e7ed085 FG |
215 | if !v.layout().ty.is_simd() { |
216 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
217 | return; | |
218 | } | |
219 | ||
29967ef6 XL |
220 | let idx_const = if let Some(idx_const) = crate::constant::mir_operand_get_const_val(fx, idx) { |
221 | idx_const | |
222 | } else { | |
fc512014 | 223 | fx.tcx.sess.span_warn( |
29967ef6 XL |
224 | span, |
225 | "Index argument for `simd_extract` is not a constant", | |
226 | ); | |
fc512014 XL |
227 | let res = crate::trap::trap_unimplemented_ret_value( |
228 | fx, | |
229 | ret.layout(), | |
230 | "Index argument for `simd_extract` is not a constant", | |
231 | ); | |
232 | ret.write_cvalue(fx, res); | |
233 | return; | |
29967ef6 XL |
234 | }; |
235 | ||
6a06907d | 236 | let idx = idx_const.try_to_bits(Size::from_bytes(4 /* u32*/)).unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); |
5869c6ff | 237 | let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); |
29967ef6 XL |
238 | if idx >= lane_count.into() { |
239 | fx.tcx.sess.span_fatal(fx.mir.span, &format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count)); | |
240 | } | |
241 | ||
94222f64 | 242 | let ret_lane = v.value_lane(fx, idx.try_into().unwrap()); |
29967ef6 XL |
243 | ret.write_cvalue(fx, ret_lane); |
244 | }; | |
245 | ||
94222f64 | 246 | simd_neg, (c a) { |
5e7ed085 FG |
247 | if !a.layout().ty.is_simd() { |
248 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
249 | return; | |
250 | } | |
251 | ||
252 | simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { | |
253 | match lane_ty.kind() { | |
94222f64 XL |
254 | ty::Int(_) => fx.bcx.ins().ineg(lane), |
255 | ty::Float(_) => fx.bcx.ins().fneg(lane), | |
256 | _ => unreachable!(), | |
5e7ed085 | 257 | } |
94222f64 XL |
258 | }); |
259 | }; | |
260 | ||
5e7ed085 FG |
261 | simd_add | simd_sub | simd_mul | simd_div | simd_rem |
262 | | simd_shl | simd_shr | simd_and | simd_or | simd_xor, (c x, c y) { | |
263 | if !x.layout().ty.is_simd() { | |
264 | report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); | |
265 | return; | |
266 | } | |
94222f64 | 267 | |
5e7ed085 FG |
268 | // FIXME use vector instructions when possible |
269 | simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| match ( | |
270 | lane_ty.kind(), | |
271 | intrinsic, | |
272 | ) { | |
273 | (ty::Uint(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), | |
274 | (ty::Uint(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), | |
275 | (ty::Uint(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), | |
276 | (ty::Uint(_), sym::simd_div) => fx.bcx.ins().udiv(x_lane, y_lane), | |
277 | (ty::Uint(_), sym::simd_rem) => fx.bcx.ins().urem(x_lane, y_lane), | |
278 | ||
279 | (ty::Int(_), sym::simd_add) => fx.bcx.ins().iadd(x_lane, y_lane), | |
280 | (ty::Int(_), sym::simd_sub) => fx.bcx.ins().isub(x_lane, y_lane), | |
281 | (ty::Int(_), sym::simd_mul) => fx.bcx.ins().imul(x_lane, y_lane), | |
282 | (ty::Int(_), sym::simd_div) => fx.bcx.ins().sdiv(x_lane, y_lane), | |
283 | (ty::Int(_), sym::simd_rem) => fx.bcx.ins().srem(x_lane, y_lane), | |
284 | ||
285 | (ty::Float(_), sym::simd_add) => fx.bcx.ins().fadd(x_lane, y_lane), | |
286 | (ty::Float(_), sym::simd_sub) => fx.bcx.ins().fsub(x_lane, y_lane), | |
287 | (ty::Float(_), sym::simd_mul) => fx.bcx.ins().fmul(x_lane, y_lane), | |
288 | (ty::Float(_), sym::simd_div) => fx.bcx.ins().fdiv(x_lane, y_lane), | |
289 | (ty::Float(FloatTy::F32), sym::simd_rem) => fx.lib_call( | |
290 | "fmodf", | |
291 | vec![AbiParam::new(types::F32), AbiParam::new(types::F32)], | |
292 | vec![AbiParam::new(types::F32)], | |
293 | &[x_lane, y_lane], | |
294 | )[0], | |
295 | (ty::Float(FloatTy::F64), sym::simd_rem) => fx.lib_call( | |
296 | "fmod", | |
297 | vec![AbiParam::new(types::F64), AbiParam::new(types::F64)], | |
298 | vec![AbiParam::new(types::F64)], | |
299 | &[x_lane, y_lane], | |
300 | )[0], | |
301 | ||
302 | (ty::Uint(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), | |
303 | (ty::Uint(_), sym::simd_shr) => fx.bcx.ins().ushr(x_lane, y_lane), | |
304 | (ty::Uint(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), | |
305 | (ty::Uint(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), | |
306 | (ty::Uint(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), | |
307 | ||
308 | (ty::Int(_), sym::simd_shl) => fx.bcx.ins().ishl(x_lane, y_lane), | |
309 | (ty::Int(_), sym::simd_shr) => fx.bcx.ins().sshr(x_lane, y_lane), | |
310 | (ty::Int(_), sym::simd_and) => fx.bcx.ins().band(x_lane, y_lane), | |
311 | (ty::Int(_), sym::simd_or) => fx.bcx.ins().bor(x_lane, y_lane), | |
312 | (ty::Int(_), sym::simd_xor) => fx.bcx.ins().bxor(x_lane, y_lane), | |
313 | ||
314 | _ => unreachable!(), | |
94222f64 XL |
315 | }); |
316 | }; | |
317 | ||
29967ef6 | 318 | simd_fma, (c a, c b, c c) { |
5e7ed085 FG |
319 | if !a.layout().ty.is_simd() { |
320 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
321 | return; | |
322 | } | |
29967ef6 XL |
323 | assert_eq!(a.layout(), b.layout()); |
324 | assert_eq!(a.layout(), c.layout()); | |
325 | let layout = a.layout(); | |
326 | ||
5869c6ff XL |
327 | let (lane_count, _lane_ty) = layout.ty.simd_size_and_type(fx.tcx); |
328 | let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); | |
29967ef6 | 329 | assert_eq!(lane_count, ret_lane_count); |
5869c6ff | 330 | let ret_lane_layout = fx.layout_of(ret_lane_ty); |
29967ef6 XL |
331 | |
332 | for lane in 0..lane_count { | |
94222f64 XL |
333 | let a_lane = a.value_lane(fx, lane).load_scalar(fx); |
334 | let b_lane = b.value_lane(fx, lane).load_scalar(fx); | |
335 | let c_lane = c.value_lane(fx, lane).load_scalar(fx); | |
29967ef6 XL |
336 | |
337 | let mul_lane = fx.bcx.ins().fmul(a_lane, b_lane); | |
338 | let res_lane = CValue::by_val(fx.bcx.ins().fadd(mul_lane, c_lane), ret_lane_layout); | |
339 | ||
94222f64 | 340 | ret.place_lane(fx, lane).write_cvalue(fx, res_lane); |
29967ef6 XL |
341 | } |
342 | }; | |
343 | ||
5e7ed085 FG |
344 | simd_fmin | simd_fmax, (c x, c y) { |
345 | if !x.layout().ty.is_simd() { | |
346 | report_simd_type_validation_error(fx, intrinsic, span, x.layout().ty); | |
347 | return; | |
348 | } | |
349 | ||
350 | // FIXME use vector instructions when possible | |
351 | simd_pair_for_each_lane(fx, x, y, ret, &|fx, lane_ty, _ret_lane_ty, x_lane, y_lane| { | |
352 | match lane_ty.kind() { | |
353 | ty::Float(_) => {}, | |
354 | _ => unreachable!("{:?}", lane_ty), | |
355 | } | |
356 | match intrinsic { | |
357 | sym::simd_fmin => fx.bcx.ins().fmin(x_lane, y_lane), | |
358 | sym::simd_fmax => fx.bcx.ins().fmax(x_lane, y_lane), | |
359 | _ => unreachable!(), | |
360 | } | |
361 | }); | |
29967ef6 XL |
362 | }; |
363 | ||
94222f64 | 364 | simd_round, (c a) { |
5e7ed085 FG |
365 | if !a.layout().ty.is_simd() { |
366 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
367 | return; | |
368 | } | |
369 | ||
370 | simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { | |
371 | match lane_ty.kind() { | |
94222f64 XL |
372 | ty::Float(FloatTy::F32) => fx.lib_call( |
373 | "roundf", | |
374 | vec![AbiParam::new(types::F32)], | |
375 | vec![AbiParam::new(types::F32)], | |
376 | &[lane], | |
377 | )[0], | |
378 | ty::Float(FloatTy::F64) => fx.lib_call( | |
379 | "round", | |
380 | vec![AbiParam::new(types::F64)], | |
381 | vec![AbiParam::new(types::F64)], | |
382 | &[lane], | |
383 | )[0], | |
5e7ed085 FG |
384 | _ => unreachable!("{:?}", lane_ty), |
385 | } | |
94222f64 XL |
386 | }); |
387 | }; | |
5e7ed085 FG |
388 | |
389 | simd_fabs | simd_fsqrt | simd_ceil | simd_floor | simd_trunc, (c a) { | |
390 | if !a.layout().ty.is_simd() { | |
391 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
392 | return; | |
393 | } | |
394 | ||
395 | simd_for_each_lane(fx, a, ret, &|fx, lane_ty, _ret_lane_ty, lane| { | |
396 | match lane_ty.kind() { | |
397 | ty::Float(_) => {}, | |
398 | _ => unreachable!("{:?}", lane_ty), | |
399 | } | |
400 | match intrinsic { | |
401 | sym::simd_fabs => fx.bcx.ins().fabs(lane), | |
402 | sym::simd_fsqrt => fx.bcx.ins().sqrt(lane), | |
403 | sym::simd_ceil => fx.bcx.ins().ceil(lane), | |
404 | sym::simd_floor => fx.bcx.ins().floor(lane), | |
405 | sym::simd_trunc => fx.bcx.ins().trunc(lane), | |
406 | _ => unreachable!(), | |
407 | } | |
94222f64 XL |
408 | }); |
409 | }; | |
410 | ||
411 | simd_reduce_add_ordered | simd_reduce_add_unordered, (c v, v acc) { | |
5e7ed085 FG |
412 | // FIXME there must be no acc param for integer vectors |
413 | if !v.layout().ty.is_simd() { | |
414 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
415 | return; | |
416 | } | |
417 | ||
418 | simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { | |
419 | if lane_ty.is_floating_point() { | |
fc512014 XL |
420 | fx.bcx.ins().fadd(a, b) |
421 | } else { | |
422 | fx.bcx.ins().iadd(a, b) | |
423 | } | |
424 | }); | |
425 | }; | |
426 | ||
94222f64 | 427 | simd_reduce_mul_ordered | simd_reduce_mul_unordered, (c v, v acc) { |
5e7ed085 FG |
428 | // FIXME there must be no acc param for integer vectors |
429 | if !v.layout().ty.is_simd() { | |
430 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
431 | return; | |
432 | } | |
433 | ||
434 | simd_reduce(fx, v, Some(acc), ret, &|fx, lane_ty, a, b| { | |
435 | if lane_ty.is_floating_point() { | |
fc512014 XL |
436 | fx.bcx.ins().fmul(a, b) |
437 | } else { | |
438 | fx.bcx.ins().imul(a, b) | |
439 | } | |
440 | }); | |
441 | }; | |
442 | ||
443 | simd_reduce_all, (c v) { | |
5e7ed085 FG |
444 | if !v.layout().ty.is_simd() { |
445 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
446 | return; | |
447 | } | |
448 | ||
449 | simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().band(a, b)); | |
fc512014 XL |
450 | }; |
451 | ||
452 | simd_reduce_any, (c v) { | |
5e7ed085 FG |
453 | if !v.layout().ty.is_simd() { |
454 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
455 | return; | |
456 | } | |
457 | ||
458 | simd_reduce_bool(fx, v, ret, &|fx, a, b| fx.bcx.ins().bor(a, b)); | |
fc512014 XL |
459 | }; |
460 | ||
94222f64 | 461 | simd_reduce_and, (c v) { |
5e7ed085 FG |
462 | if !v.layout().ty.is_simd() { |
463 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
464 | return; | |
465 | } | |
466 | ||
467 | simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().band(a, b)); | |
94222f64 XL |
468 | }; |
469 | ||
470 | simd_reduce_or, (c v) { | |
5e7ed085 FG |
471 | if !v.layout().ty.is_simd() { |
472 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
473 | return; | |
474 | } | |
475 | ||
476 | simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bor(a, b)); | |
94222f64 XL |
477 | }; |
478 | ||
479 | simd_reduce_xor, (c v) { | |
5e7ed085 FG |
480 | if !v.layout().ty.is_simd() { |
481 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
482 | return; | |
483 | } | |
484 | ||
485 | simd_reduce(fx, v, None, ret, &|fx, _ty, a, b| fx.bcx.ins().bxor(a, b)); | |
94222f64 XL |
486 | }; |
487 | ||
488 | simd_reduce_min, (c v) { | |
5e7ed085 FG |
489 | if !v.layout().ty.is_simd() { |
490 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
491 | return; | |
492 | } | |
493 | ||
494 | simd_reduce(fx, v, None, ret, &|fx, ty, a, b| { | |
495 | let lt = match ty.kind() { | |
a2a8927a XL |
496 | ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedLessThan, a, b), |
497 | ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedLessThan, a, b), | |
498 | ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::LessThan, a, b), | |
499 | _ => unreachable!(), | |
500 | }; | |
94222f64 XL |
501 | fx.bcx.ins().select(lt, a, b) |
502 | }); | |
503 | }; | |
504 | ||
505 | simd_reduce_max, (c v) { | |
5e7ed085 FG |
506 | if !v.layout().ty.is_simd() { |
507 | report_simd_type_validation_error(fx, intrinsic, span, v.layout().ty); | |
508 | return; | |
509 | } | |
510 | ||
511 | simd_reduce(fx, v, None, ret, &|fx, ty, a, b| { | |
512 | let gt = match ty.kind() { | |
a2a8927a XL |
513 | ty::Int(_) => fx.bcx.ins().icmp(IntCC::SignedGreaterThan, a, b), |
514 | ty::Uint(_) => fx.bcx.ins().icmp(IntCC::UnsignedGreaterThan, a, b), | |
515 | ty::Float(_) => fx.bcx.ins().fcmp(FloatCC::GreaterThan, a, b), | |
516 | _ => unreachable!(), | |
517 | }; | |
94222f64 XL |
518 | fx.bcx.ins().select(gt, a, b) |
519 | }); | |
520 | }; | |
521 | ||
522 | simd_select, (c m, c a, c b) { | |
5e7ed085 FG |
523 | if !m.layout().ty.is_simd() { |
524 | report_simd_type_validation_error(fx, intrinsic, span, m.layout().ty); | |
525 | return; | |
526 | } | |
527 | if !a.layout().ty.is_simd() { | |
528 | report_simd_type_validation_error(fx, intrinsic, span, a.layout().ty); | |
529 | return; | |
530 | } | |
94222f64 XL |
531 | assert_eq!(a.layout(), b.layout()); |
532 | ||
533 | let (lane_count, lane_ty) = a.layout().ty.simd_size_and_type(fx.tcx); | |
534 | let lane_layout = fx.layout_of(lane_ty); | |
535 | ||
536 | for lane in 0..lane_count { | |
537 | let m_lane = m.value_lane(fx, lane).load_scalar(fx); | |
538 | let a_lane = a.value_lane(fx, lane).load_scalar(fx); | |
539 | let b_lane = b.value_lane(fx, lane).load_scalar(fx); | |
540 | ||
541 | let m_lane = fx.bcx.ins().icmp_imm(IntCC::Equal, m_lane, 0); | |
542 | let res_lane = CValue::by_val(fx.bcx.ins().select(m_lane, b_lane, a_lane), lane_layout); | |
543 | ||
544 | ret.place_lane(fx, lane).write_cvalue(fx, res_lane); | |
545 | } | |
546 | }; | |
547 | ||
548 | // simd_saturating_* | |
29967ef6 | 549 | // simd_bitmask |
94222f64 XL |
550 | // simd_scatter |
551 | // simd_gather | |
29967ef6 XL |
552 | } |
553 | } |