]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/type_.rs
2ef90bca5ac20d7db69d6581ee1ff72e589874d1
[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};
5 use rustc_codegen_ssa::common::TypeKind;
6 use rustc_middle::bug;
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         let bytes = (num_bits / 8).next_power_of_two() as i32;
18         match bytes {
19             1 => self.i8_type,
20             2 => self.i16_type,
21             4 => self.i32_type,
22             8 => self.i64_type,
23             16 => self.i128_type,
24             _ => panic!("unexpected num_bits: {}", num_bits),
25         }
26         /*
27         let bytes = (num_bits / 8).next_power_of_two() as i32;
28         println!("num_bits: {}, bytes: {}", num_bits, bytes);
29         self.context.new_int_type(bytes, true) // TODO: check if it is indeed a signed integer.
30         */
31     }
32
33     /*pub fn type_bool(&self) -> Type<'gcc> {
34         self.bool_type
35     }*/
36
37     pub fn type_void(&self) -> Type<'gcc> {
38         self.context.new_type::<()>()
39     }
40
41     pub fn type_size_t(&self) -> Type<'gcc> {
42         self.context.new_type::<usize>()
43     }
44
45     pub fn type_u8(&self) -> Type<'gcc> {
46         self.u8_type
47     }
48
49     pub fn type_u16(&self) -> Type<'gcc> {
50         self.u16_type
51     }
52
53     pub fn type_u32(&self) -> Type<'gcc> {
54         self.u32_type
55     }
56
57     pub fn type_u64(&self) -> Type<'gcc> {
58         self.u64_type
59     }
60
61     pub fn type_u128(&self) -> Type<'gcc> {
62         self.u128_type
63     }
64
65     pub fn type_pointee_for_align(&self, align: Align) -> Type<'gcc> {
66         // FIXME(eddyb) We could find a better approximation if ity.align < align.
67         let ity = Integer::approximate_align(self, align);
68         self.type_from_integer(ity)
69     }
70
71     /*pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> {
72         match t {
73             ty::IntTy::Isize => self.type_isize(),
74             ty::IntTy::I8 => self.type_i8(),
75             ty::IntTy::I16 => self.type_i16(),
76             ty::IntTy::I32 => self.type_i32(),
77             ty::IntTy::I64 => self.type_i64(),
78             ty::IntTy::I128 => self.type_i128(),
79         }
80     }
81
82     pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> {
83         match t {
84             ty::UintTy::Usize => self.type_isize(),
85             ty::UintTy::U8 => self.type_i8(),
86             ty::UintTy::U16 => self.type_i16(),
87             ty::UintTy::U32 => self.type_i32(),
88             ty::UintTy::U64 => self.type_i64(),
89             ty::UintTy::U128 => self.type_i128(),
90         }
91     }
92
93     pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> {
94         match t {
95             ty::FloatTy::F32 => self.type_f32(),
96             ty::FloatTy::F64 => self.type_f64(),
97         }
98     }
99
100     pub fn type_vector(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
101         self.context.new_vector_type(ty, len)
102     }*/
103 }
104
105 impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
106     fn type_i1(&self) -> Type<'gcc> {
107         self.bool_type
108     }
109
110     fn type_i8(&self) -> Type<'gcc> {
111         self.i8_type
112     }
113
114     fn type_i16(&self) -> Type<'gcc> {
115         self.i16_type
116     }
117
118     fn type_i32(&self) -> Type<'gcc> {
119         self.i32_type
120     }
121
122     fn type_i64(&self) -> Type<'gcc> {
123         self.i64_type
124     }
125
126     fn type_i128(&self) -> Type<'gcc> {
127         self.i128_type
128     }
129
130     fn type_isize(&self) -> Type<'gcc> {
131         self.isize_type
132     }
133
134     fn type_f32(&self) -> Type<'gcc> {
135         self.context.new_type::<f32>()
136     }
137
138     fn type_f64(&self) -> Type<'gcc> {
139         self.context.new_type::<f64>()
140     }
141
142     fn type_func(&self, params: &[Type<'gcc>], return_type: Type<'gcc>) -> Type<'gcc> {
143         self.context.new_function_pointer_type(None, return_type, params, false)
144     }
145
146     fn type_struct(&self, fields: &[Type<'gcc>], _packed: bool) -> Type<'gcc> {
147         let types = fields.to_vec();
148         if let Some(typ) = self.struct_types.borrow().get(fields) {
149             return typ.clone();
150         }
151         let fields: Vec<_> = fields.iter().enumerate()
152             .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
153             .collect();
154         // TODO: use packed.
155         //let name = types.iter().map(|typ| format!("{:?}", typ)).collect::<Vec<_>>().join("_");
156         //let typ = self.context.new_struct_type(None, format!("struct{}", name), &fields).as_type();
157         let typ = self.context.new_struct_type(None, "struct", &fields).as_type();
158         self.struct_types.borrow_mut().insert(types, typ);
159         typ
160     }
161
162     fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
163         if typ.is_integral() {
164             TypeKind::Integer
165         }
166         else if typ.is_vector().is_some() {
167             TypeKind::Vector
168         }
169         else {
170             // TODO
171             TypeKind::Void
172         }
173     }
174
175     fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
176         // TODO
177         /*assert_ne!(self.type_kind(ty), TypeKind::Function,
178             "don't call ptr_to on function types, use ptr_to_gcc_type on FnAbi instead"
179         );*/
180         ty.make_pointer()
181     }
182
183     fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
184         // TODO: use address_space
185         ty.make_pointer()
186     }
187
188     fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
189         if let Some(typ) = ty.is_array() {
190             typ
191         }
192         else if let Some(vector_type) = ty.is_vector() {
193             vector_type.get_element_type()
194         }
195         else if let Some(typ) = ty.get_pointee() {
196             typ
197         }
198         else {
199             unreachable!()
200         }
201     }
202
203     fn vector_length(&self, _ty: Type<'gcc>) -> usize {
204         unimplemented!();
205         //unsafe { llvm::LLVMGetVectorSize(ty) as usize }
206     }
207
208     fn float_width(&self, typ: Type<'gcc>) -> usize {
209         let f32 = self.context.new_type::<f32>();
210         let f64 = self.context.new_type::<f64>();
211         if typ == f32 {
212             32
213         }
214         else if typ == f64 {
215             64
216         }
217         else {
218             panic!("Cannot get width of float type {:?}", typ);
219         }
220         // TODO: support other sizes.
221         /*match self.type_kind(ty) {
222             TypeKind::Float => 32,
223             TypeKind::Double => 64,
224             TypeKind::X86_FP80 => 80,
225             TypeKind::FP128 | TypeKind::PPC_FP128 => 128,
226             _ => bug!("llvm_float_width called on a non-float type"),
227         }*/
228     }
229
230     fn int_width(&self, typ: Type<'gcc>) -> u64 {
231         if typ.is_i8(self) || typ.is_u8(self) {
232             8
233         }
234         else if typ.is_i16(self) || typ.is_u16(self) {
235             16
236         }
237         else if typ.is_i32(self) || typ.is_u32(self) {
238             32
239         }
240         else if typ.is_i64(self) || typ.is_u64(self) {
241             64
242         }
243         else if typ.is_i128(self) || typ.is_u128(self) {
244             128
245         }
246         else {
247             panic!("Cannot get width of int type {:?}", typ);
248         }
249     }
250
251     fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
252         value.get_type()
253     }
254 }
255
256 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
257     pub fn type_padding_filler(&self, size: Size, align: Align) -> Type<'gcc> {
258         let unit = Integer::approximate_align(self, align);
259         let size = size.bytes();
260         let unit_size = unit.size().bytes();
261         assert_eq!(size % unit_size, 0);
262         self.type_array(self.type_from_integer(unit), size / unit_size)
263     }
264
265     pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
266         // TODO: use packed.
267         let fields: Vec<_> = fields.iter().enumerate()
268             .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
269             .collect();
270         typ.set_fields(None, &fields);
271     }
272
273     /*fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
274         // TODO: use packed.
275         let fields: Vec<_> = fields.iter().enumerate()
276             .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
277             .collect();
278         return self.context.new_struct_type(None, "unnamedStruct", &fields).as_type();
279     }*/
280
281     pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
282         self.context.new_opaque_struct_type(None, name)
283     }
284
285     pub fn type_array(&self, ty: Type<'gcc>, mut len: u64) -> Type<'gcc> {
286         if let Some(struct_type) = ty.is_struct() {
287             if struct_type.get_field_count() == 0 {
288                 // NOTE: since gccjit only supports i32 for the array size and libcore's tests uses a
289                 // size of usize::MAX in test_binary_search, we workaround this by setting the size to
290                 // zero for ZSTs.
291                 // FIXME: fix gccjit API.
292                 len = 0;
293             }
294         }
295
296         // NOTE: see note above. Some other test uses usize::MAX.
297         if len == u64::MAX {
298             len = 0;
299         }
300
301         let len: i32 = len.try_into().expect("array len");
302
303         self.context.new_array_type(None, ty, len)
304     }
305 }
306
307 pub fn struct_fields<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>) -> (Vec<Type<'gcc>>, bool) {
308     //debug!("struct_fields: {:#?}", layout);
309     let field_count = layout.fields.count();
310
311     let mut packed = false;
312     let mut offset = Size::ZERO;
313     let mut prev_effective_align = layout.align.abi;
314     let mut result: Vec<_> = Vec::with_capacity(1 + field_count * 2);
315     for i in layout.fields.index_by_increasing_offset() {
316         let target_offset = layout.fields.offset(i as usize);
317         let field = layout.field(cx, i);
318         let effective_field_align =
319             layout.align.abi.min(field.align.abi).restrict_for_offset(target_offset);
320         packed |= effective_field_align < field.align.abi;
321
322         /*debug!(
323             "struct_fields: {}: {:?} offset: {:?} target_offset: {:?} \
324                 effective_field_align: {}",
325             i,
326             field,
327             offset,
328             target_offset,
329             effective_field_align.bytes()
330         );*/
331         assert!(target_offset >= offset);
332         let padding = target_offset - offset;
333         let padding_align = prev_effective_align.min(effective_field_align);
334         assert_eq!(offset.align_to(padding_align) + padding, target_offset);
335         result.push(cx.type_padding_filler(padding, padding_align));
336         //debug!("    padding before: {:?}", padding);
337
338         result.push(field.gcc_type(cx, !field.ty.is_any_ptr())); // FIXME: might need to check if the type is inside another, like Box<Type>.
339         offset = target_offset + field.size;
340         prev_effective_align = effective_field_align;
341     }
342     if !layout.is_unsized() && field_count > 0 {
343         if offset > layout.size {
344             bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
345         }
346         let padding = layout.size - offset;
347         let padding_align = prev_effective_align;
348         assert_eq!(offset.align_to(padding_align) + padding, layout.size);
349         /*debug!(
350             "struct_fields: pad_bytes: {:?} offset: {:?} stride: {:?}",
351             padding, offset, layout.size
352         );*/
353         result.push(cx.type_padding_filler(padding, padding_align));
354         assert_eq!(result.len(), 1 + field_count * 2);
355     } else {
356         //debug!("struct_fields: offset: {:?} stride: {:?}", offset, layout.size);
357     }
358
359     (result, packed)
360 }