]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/intrinsic/simd.rs
Merge commit 'e228f0c16ea8c34794a6285bf57aab627c26b147' into libgccjit-codegen
[rust.git] / compiler / rustc_codegen_gcc / src / intrinsic / simd.rs
1 use gccjit::{RValue, Type};
2 use rustc_codegen_ssa::base::compare_simd_types;
3 use rustc_codegen_ssa::common::{TypeKind, span_invalid_monomorphization_error};
4 use rustc_codegen_ssa::mir::operand::OperandRef;
5 use rustc_codegen_ssa::traits::{BaseTypeMethods, BuilderMethods};
6 use rustc_hir as hir;
7 use rustc_middle::span_bug;
8 use rustc_middle::ty::layout::HasTyCtxt;
9 use rustc_middle::ty::{self, Ty};
10 use rustc_span::{Span, Symbol, sym};
11
12 use crate::builder::Builder;
13
14 pub 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 }