]>
Commit | Line | Data |
---|---|---|
c295e0f8 XL |
1 | use std::convert::TryInto; |
2 | ||
3 | use gccjit::{RValue, Struct, Type}; | |
064997fb | 4 | use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods}; |
c295e0f8 | 5 | use rustc_codegen_ssa::common::TypeKind; |
923072b8 | 6 | use rustc_middle::{bug, ty}; |
c295e0f8 XL |
7 | use rustc_middle::ty::layout::TyAndLayout; |
8 | use rustc_target::abi::{AddressSpace, Align, Integer, Size}; | |
9 | ||
923072b8 | 10 | use crate::common::TypeReflection; |
c295e0f8 XL |
11 | use crate::context::CodegenCx; |
12 | use crate::type_of::LayoutGccExt; | |
13 | ||
14 | impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { | |
15 | pub fn type_ix(&self, num_bits: u64) -> Type<'gcc> { | |
16 | // gcc only supports 1, 2, 4 or 8-byte integers. | |
17 | // FIXME(antoyo): this is misleading to use the next power of two as rustc_codegen_ssa | |
18 | // sometimes use 96-bit numbers and the following code will give an integer of a different | |
19 | // size. | |
20 | let bytes = (num_bits / 8).next_power_of_two() as i32; | |
21 | match bytes { | |
22 | 1 => self.i8_type, | |
23 | 2 => self.i16_type, | |
24 | 4 => self.i32_type, | |
25 | 8 => self.i64_type, | |
26 | 16 => self.i128_type, | |
27 | _ => panic!("unexpected num_bits: {}", num_bits), | |
28 | } | |
29 | } | |
30 | ||
31 | pub fn type_void(&self) -> Type<'gcc> { | |
32 | self.context.new_type::<()>() | |
33 | } | |
34 | ||
35 | pub fn type_size_t(&self) -> Type<'gcc> { | |
36 | self.context.new_type::<usize>() | |
37 | } | |
38 | ||
39 | pub fn type_u8(&self) -> Type<'gcc> { | |
40 | self.u8_type | |
41 | } | |
42 | ||
43 | pub fn type_u16(&self) -> Type<'gcc> { | |
44 | self.u16_type | |
45 | } | |
46 | ||
47 | pub fn type_u32(&self) -> Type<'gcc> { | |
48 | self.u32_type | |
49 | } | |
50 | ||
51 | pub fn type_u64(&self) -> Type<'gcc> { | |
52 | self.u64_type | |
53 | } | |
54 | ||
55 | pub fn type_u128(&self) -> Type<'gcc> { | |
56 | self.u128_type | |
57 | } | |
58 | ||
59 | pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> { | |
60 | // FIXME(eddyb) We could find a better approximation if ity.align < align. | |
61 | let ity = Integer::approximate_align(self, align); | |
62 | self.type_from_integer(ity) | |
63 | } | |
923072b8 FG |
64 | |
65 | pub fn type_vector(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> { | |
66 | self.context.new_vector_type(ty, len) | |
67 | } | |
68 | ||
69 | pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> { | |
70 | match t { | |
71 | ty::FloatTy::F32 => self.type_f32(), | |
72 | ty::FloatTy::F64 => self.type_f64(), | |
73 | } | |
74 | } | |
c295e0f8 XL |
75 | } |
76 | ||
77 | impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> { | |
78 | fn type_i1(&self) -> Type<'gcc> { | |
79 | self.bool_type | |
80 | } | |
81 | ||
82 | fn type_i8(&self) -> Type<'gcc> { | |
83 | self.i8_type | |
84 | } | |
85 | ||
86 | fn type_i16(&self) -> Type<'gcc> { | |
87 | self.i16_type | |
88 | } | |
89 | ||
90 | fn type_i32(&self) -> Type<'gcc> { | |
91 | self.i32_type | |
92 | } | |
93 | ||
94 | fn type_i64(&self) -> Type<'gcc> { | |
95 | self.i64_type | |
96 | } | |
97 | ||
98 | fn type_i128(&self) -> Type<'gcc> { | |
99 | self.i128_type | |
100 | } | |
101 | ||
102 | fn type_isize(&self) -> Type<'gcc> { | |
103 | self.isize_type | |
104 | } | |
105 | ||
106 | fn type_f32(&self) -> Type<'gcc> { | |
107 | self.context.new_type::<f32>() | |
108 | } | |
109 | ||
110 | fn type_f64(&self) -> Type<'gcc> { | |
111 | self.context.new_type::<f64>() | |
112 | } | |
113 | ||
114 | fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> { | |
115 | self.context.new_function_pointer_type(None, return_type, params, false) | |
116 | } | |
117 | ||
923072b8 | 118 | fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> { |
c295e0f8 XL |
119 | let types = fields.to_vec(); |
120 | if let Some(typ) = self.struct_types.borrow().get(fields) { | |
121 | return typ.clone(); | |
122 | } | |
123 | let fields: Vec<_> = fields.iter().enumerate() | |
124 | .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index))) | |
125 | .collect(); | |
c295e0f8 | 126 | let typ = self.context.new_struct_type(None, "struct", &fields).as_type(); |
923072b8 FG |
127 | if packed { |
128 | #[cfg(feature="master")] | |
129 | typ.set_packed(); | |
130 | } | |
c295e0f8 XL |
131 | self.struct_types.borrow_mut().insert(types, typ); |
132 | typ | |
133 | } | |
134 | ||
135 | fn type_kind(&self, typ: Type<'gcc>) -> TypeKind { | |
5e7ed085 | 136 | if self.is_int_type_or_bool(typ) { |
c295e0f8 XL |
137 | TypeKind::Integer |
138 | } | |
5e7ed085 FG |
139 | else if typ.is_compatible_with(self.float_type) { |
140 | TypeKind::Float | |
141 | } | |
142 | else if typ.is_compatible_with(self.double_type) { | |
143 | TypeKind::Double | |
144 | } | |
923072b8 | 145 | else if typ.is_vector() { |
c295e0f8 XL |
146 | TypeKind::Vector |
147 | } | |
148 | else { | |
149 | // TODO(antoyo): support other types. | |
150 | TypeKind::Void | |
151 | } | |
152 | } | |
153 | ||
154 | fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> { | |
155 | ty.make_pointer() | |
156 | } | |
157 | ||
158 | fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> { | |
923072b8 | 159 | // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE? |
c295e0f8 XL |
160 | ty.make_pointer() |
161 | } | |
162 | ||
163 | fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> { | |
a2a8927a | 164 | if let Some(typ) = ty.dyncast_array() { |
c295e0f8 XL |
165 | typ |
166 | } | |
a2a8927a | 167 | else if let Some(vector_type) = ty.dyncast_vector() { |
c295e0f8 XL |
168 | vector_type.get_element_type() |
169 | } | |
170 | else if let Some(typ) = ty.get_pointee() { | |
171 | typ | |
172 | } | |
173 | else { | |
174 | unreachable!() | |
175 | } | |
176 | } | |
177 | ||
178 | fn vector_length(&self, _ty: Type<'gcc>) -> usize { | |
179 | unimplemented!(); | |
180 | } | |
181 | ||
182 | fn float_width(&self, typ: Type<'gcc>) -> usize { | |
183 | let f32 = self.context.new_type::<f32>(); | |
184 | let f64 = self.context.new_type::<f64>(); | |
923072b8 | 185 | if typ.is_compatible_with(f32) { |
c295e0f8 XL |
186 | 32 |
187 | } | |
923072b8 | 188 | else if typ.is_compatible_with(f64) { |
c295e0f8 XL |
189 | 64 |
190 | } | |
191 | else { | |
192 | panic!("Cannot get width of float type {:?}", typ); | |
193 | } | |
194 | // TODO(antoyo): support other sizes. | |
195 | } | |
196 | ||
197 | fn int_width(&self, typ: Type<'gcc>) -> u64 { | |
5e7ed085 | 198 | self.gcc_int_width(typ) |
c295e0f8 XL |
199 | } |
200 | ||
201 | fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> { | |
202 | value.get_type() | |
203 | } | |
487cf647 FG |
204 | |
205 | fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> { | |
206 | if let Some(struct_type) = ty.is_struct() { | |
207 | if struct_type.get_field_count() == 0 { | |
208 | // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a | |
209 | // size of usize::MAX in test_binary_search, we workaround this by setting the size to | |
210 | // zero for ZSTs. | |
211 | // FIXME(antoyo): fix gccjit API. | |
212 | len = 0; | |
213 | } | |
214 | } | |
215 | ||
216 | // NOTE: see note above. Some other test uses usize::MAX. | |
217 | if len == u64::MAX { | |
218 | len = 0; | |
219 | } | |
220 | ||
221 | let len: i32 = len.try_into().expect("array len"); | |
222 | ||
223 | self.context.new_array_type(None, ty, len) | |
224 | } | |
c295e0f8 XL |
225 | } |
226 | ||
227 | impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> { | |
228 | pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> { | |
229 | let unit = Integer::approximate_align(self, align); | |
230 | let size = size.bytes(); | |
231 | let unit_size = unit.size().bytes(); | |
232 | assert_eq!(size % unit_size, 0); | |
233 | self.type_array(self.type_from_integer(unit), size / unit_size) | |
234 | } | |
235 | ||
923072b8 | 236 | pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) { |
c295e0f8 XL |
237 | let fields: Vec<_> = fields.iter().enumerate() |
238 | .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index))) | |
239 | .collect(); | |
240 | typ.set_fields(None, &fields); | |
923072b8 FG |
241 | if packed { |
242 | #[cfg(feature="master")] | |
243 | typ.as_type().set_packed(); | |
244 | } | |
c295e0f8 XL |
245 | } |
246 | ||
247 | pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> { | |
248 | self.context.new_opaque_struct_type(None, name) | |
249 | } | |
250 | ||
923072b8 FG |
251 | pub fn type_bool(&self) -> Type<'gcc> { |
252 | self.context.new_type::<bool>() | |
253 | } | |
c295e0f8 XL |
254 | } |
255 | ||
256 | pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) { | |
257 | let field_count = layout.fields.count(); | |
258 | ||
259 | let mut packed = false; | |
260 | let mut offset = Size::ZERO; | |
261 | let mut prev_effective_align = layout.align.abi; | |
262 | let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2); | |
263 | for i in layout.fields.index_by_increasing_offset() { | |
264 | let target_offset = layout.fields.offset(i as usize); | |
265 | let field = layout.field(cx, i); | |
266 | let effective_field_align = | |
267 | layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset); | |
268 | packed |= effective_field_align < field.align.abi; | |
269 | ||
270 | assert!(target_offset >= offset); | |
271 | let padding = target_offset - offset; | |
272 | let padding_align = prev_effective_align.min(effective_field_align); | |
273 | assert_eq!(offset.align_to(padding_align) + padding, target_offset); | |
274 | result.push(cx.type_padding_filler(padding, padding_align)); | |
275 | ||
276 | result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME(antoyo): might need to check if the type is inside another, like Box<Type>. | |
277 | offset = target_offset + field.size; | |
278 | prev_effective_align = effective_field_align; | |
279 | } | |
487cf647 | 280 | if layout.is_sized() && field_count > 0 { |
c295e0f8 XL |
281 | if offset > layout.size { |
282 | bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset); | |
283 | } | |
284 | let padding = layout.size - offset; | |
285 | let padding_align = prev_effective_align; | |
286 | assert_eq!(offset.align_to(padding_align) + padding, layout.size); | |
287 | result.push(cx.type_padding_filler(padding, padding_align)); | |
288 | assert_eq!(result.len(), 1 + field_count * 2); | |
289 | } | |
290 | ||
291 | (result, packed) | |
292 | } | |
064997fb FG |
293 | |
294 | impl<'gcc, 'tcx> TypeMembershipMethods<'tcx> for CodegenCx<'gcc, 'tcx> { | |
295 | fn set_type_metadata(&self, _function: RValue<'gcc>, _typeid: String) { | |
296 | // Unsupported. | |
297 | } | |
298 | ||
299 | fn typeid_metadata(&self, _typeid: String) -> RValue<'gcc> { | |
300 | // Unsupported. | |
301 | self.context.new_rvalue_from_int(self.int_type, 0) | |
302 | } | |
9c376795 FG |
303 | |
304 | fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) { | |
305 | // Unsupported. | |
306 | } | |
064997fb | 307 | } |