]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/type_.rs
Rollup merge of #107470 - kadiwa4:bootstrap_cleanup, r=albertlarsan68
[rust.git] / compiler / rustc_codegen_gcc / src / type_.rs
1 use std::convert::TryInto;
2
3 use gccjit::{RValue, Struct, Type};
4 use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, TypeMembershipMethods};
5 use rustc_codegen_ssa::common::TypeKind;
6 use rustc_middle::{bug, ty};
7 use rustc_middle::ty::layout::TyAndLayout;
8 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
9
10 use crate::common::TypeReflection;
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     }
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     }
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
118     fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
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();
126         let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
127         if packed {
128             #[cfg(feature="master")]
129             typ.set_packed();
130         }
131         self.struct_types.borrow_mut().insert(types, typ);
132         typ
133     }
134
135     fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
136         if self.is_int_type_or_bool(typ) {
137             TypeKind::Integer
138         }
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         }
145         else if typ.is_vector() {
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> {
159         // TODO(antoyo): use address_space, perhaps with TYPE_ADDR_SPACE?
160         ty.make_pointer()
161     }
162
163     fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
164         if let Some(typ) = ty.dyncast_array() {
165             typ
166         }
167         else if let Some(vector_type) = ty.dyncast_vector() {
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>();
185         if typ.is_compatible_with(f32) {
186             32
187         }
188         else if typ.is_compatible_with(f64) {
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 {
198         self.gcc_int_width(typ)
199     }
200
201     fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
202         value.get_type()
203     }
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     }
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
236     pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], packed: bool) {
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);
241         if packed {
242             #[cfg(feature="master")]
243             typ.as_type().set_packed();
244         }
245     }
246
247     pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
248         self.context.new_opaque_struct_type(None, name)
249     }
250
251     pub fn type_bool(&self) -> Type<'gcc> {
252         self.context.new_type::<bool>()
253     }
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     }
280     if layout.is_sized() && field_count > 0 {
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 }
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     }
303
304     fn set_kcfi_type_metadata(&self, _function: RValue<'gcc>, _kcfi_typeid: u32) {
305         // Unsupported.
306     }
307 }