]> git.proxmox.com Git - rustc.git/blame - compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
New upstream version 1.57.0+dfsg1
[rustc.git] / compiler / rustc_codegen_gcc / src / intrinsic / simd.rs
CommitLineData
c295e0f8
XL
1use gccjit::{RValue, Type};
2use rustc_codegen_ssa::base::compare_simd_types;
3use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
4use rustc_codegen_ssa::mir::operand::OperandRef;
5use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
6use rustc_hir as hir;
7use rustc_middle::span_bug;
8use rustc_middle::ty::layout::HasTyCtxt;
9use rustc_middle::ty::{self, Ty};
10use rustc_span::{Span, Symbol, sym};
11
12use crate::builder::Builder;
13
14pub fn generic_simd_intrinsic<'a, 'gcc, 'tcx>(bx: &mut Builder<'a, 'gcc, 'tcx>, name: Symbol, callee_ty: Ty<'tcx>, args: &[OperandRef<'tcx, RValue<'gcc>>], ret_ty: Ty<'tcx>, llret_ty: Type<'gcc>, span: Span) -> Result<RValue<'gcc>, ()> {
15 // macros for error handling:
16 macro_rules! emit_error {
17 ($msg: tt) => {
18 emit_error!($msg, )
19 };
20 ($msg: tt, $($fmt: tt)*) => {
21 span_invalid_monomorphization_error(
22 bx.sess(), span,
23 &format!(concat!("invalid monomorphization of `{}` intrinsic: ", $msg),
24 name, $($fmt)*));
25 }
26 }
27
28 macro_rules! return_error {
29 ($($fmt: tt)*) => {
30 {
31 emit_error!($($fmt)*);
32 return Err(());
33 }
34 }
35 }
36
37 macro_rules! require {
38 ($cond: expr, $($fmt: tt)*) => {
39 if !$cond {
40 return_error!($($fmt)*);
41 }
42 };
43 }
44
45 macro_rules! require_simd {
46 ($ty: expr, $position: expr) => {
47 require!($ty.is_simd(), "expected SIMD {} type, found non-SIMD `{}`", $position, $ty)
48 };
49 }
50
51 let tcx = bx.tcx();
52 let sig =
53 tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), callee_ty.fn_sig(tcx));
54 let arg_tys = sig.inputs();
55 let name_str = &*name.as_str();
56
57 // every intrinsic below takes a SIMD vector as its first argument
58 require_simd!(arg_tys[0], "input");
59 let in_ty = arg_tys[0];
60
61 let comparison = match name {
62 sym::simd_eq => Some(hir::BinOpKind::Eq),
63 sym::simd_ne => Some(hir::BinOpKind::Ne),
64 sym::simd_lt => Some(hir::BinOpKind::Lt),
65 sym::simd_le => Some(hir::BinOpKind::Le),
66 sym::simd_gt => Some(hir::BinOpKind::Gt),
67 sym::simd_ge => Some(hir::BinOpKind::Ge),
68 _ => None,
69 };
70
71 let (in_len, in_elem) = arg_tys[0].simd_size_and_type(bx.tcx());
72 if let Some(cmp_op) = comparison {
73 require_simd!(ret_ty, "return");
74
75 let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
76 require!(
77 in_len == out_len,
78 "expected return type with length {} (same as input type `{}`), \
79 found `{}` with length {}",
80 in_len,
81 in_ty,
82 ret_ty,
83 out_len
84 );
85 require!(
86 bx.type_kind(bx.element_type(llret_ty)) == TypeKind::Integer,
87 "expected return type with integer elements, found `{}` with non-integer `{}`",
88 ret_ty,
89 out_ty
90 );
91
92 return Ok(compare_simd_types(
93 bx,
94 args[0].immediate(),
95 args[1].immediate(),
96 in_elem,
97 llret_ty,
98 cmp_op,
99 ));
100 }
101
102 if let Some(stripped) = name_str.strip_prefix("simd_shuffle") {
103 let n: u64 = stripped.parse().unwrap_or_else(|_| {
104 span_bug!(span, "bad `simd_shuffle` instruction only caught in codegen?")
105 });
106
107 require_simd!(ret_ty, "return");
108
109 let (out_len, out_ty) = ret_ty.simd_size_and_type(bx.tcx());
110 require!(
111 out_len == n,
112 "expected return type of length {}, found `{}` with length {}",
113 n,
114 ret_ty,
115 out_len
116 );
117 require!(
118 in_elem == out_ty,
119 "expected return element type `{}` (element of input `{}`), \
120 found `{}` with element type `{}`",
121 in_elem,
122 in_ty,
123 ret_ty,
124 out_ty
125 );
126
127 let vector = args[2].immediate();
128
129 return Ok(bx.shuffle_vector(
130 args[0].immediate(),
131 args[1].immediate(),
132 vector,
133 ));
134 }
135
136 macro_rules! arith_binary {
137 ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => {
138 $(if name == sym::$name {
139 match in_elem.kind() {
140 $($(ty::$p(_))|* => {
141 return Ok(bx.$call(args[0].immediate(), args[1].immediate()))
142 })*
143 _ => {},
144 }
145 require!(false,
146 "unsupported operation on `{}` with element `{}`",
147 in_ty,
148 in_elem)
149 })*
150 }
151 }
152
153 arith_binary! {
154 simd_add: Uint, Int => add, Float => fadd;
155 simd_sub: Uint, Int => sub, Float => fsub;
156 simd_mul: Uint, Int => mul, Float => fmul;
157 simd_div: Uint => udiv, Int => sdiv, Float => fdiv;
158 simd_rem: Uint => urem, Int => srem, Float => frem;
159 simd_shl: Uint, Int => shl;
160 simd_shr: Uint => lshr, Int => ashr;
161 simd_and: Uint, Int => and;
162 simd_or: Uint, Int => or; // FIXME(antoyo): calling `or` might not work on vectors.
163 simd_xor: Uint, Int => xor;
164 }
165
166 unimplemented!("simd {}", name);
167}