]> git.lizzy.rs Git - rust.git/blob - compiler/rustc_codegen_gcc/src/type_of.rs
010805808d2a34cc49cc92ad668e04b17d0f0190
[rust.git] / compiler / rustc_codegen_gcc / src / type_of.rs
1 use std::fmt::Write;
2
3 use gccjit::{Struct, Type};
4 use crate::rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods, LayoutTypeMethods};
5 use rustc_middle::bug;
6 use rustc_middle::ty::{self, Ty, TypeFoldable};
7 use rustc_middle::ty::layout::{FnAbiExt, TyAndLayout};
8 use rustc_middle::ty::print::with_no_trimmed_paths;
9 use rustc_target::abi::{self, Abi, F32, F64, FieldsShape, Int, Integer, LayoutOf, Pointer, PointeeInfo, Size, TyAndLayoutMethods, Variants};
10 use rustc_target::abi::call::{CastTarget, FnAbi, Reg};
11
12 use crate::abi::{FnAbiGccExt, GccType};
13 use crate::context::CodegenCx;
14 use crate::type_::struct_fields;
15
16 impl<'gcc, 'tcx> CodegenCx<'gcc, 'tcx> {
17     fn type_from_unsigned_integer(&self, i: Integer) -> Type<'gcc> {
18         use Integer::*;
19         match i {
20             I8 => self.type_u8(),
21             I16 => self.type_u16(),
22             I32 => self.type_u32(),
23             I64 => self.type_u64(),
24             I128 => self.type_u128(),
25         }
26     }
27 }
28
29 pub fn uncached_gcc_type<'gcc, 'tcx>(cx: &CodegenCx<'gcc, 'tcx>, layout: TyAndLayout<'tcx>, defer: &mut Option<(Struct<'gcc>, TyAndLayout<'tcx>)>) -> Type<'gcc> {
30     match layout.abi {
31         Abi::Scalar(_) => bug!("handled elsewhere"),
32         Abi::Vector { ref element, count } => {
33             let element = layout.scalar_gcc_type_at(cx, element, Size::ZERO);
34             return cx.context.new_vector_type(element, count);
35         },
36         Abi::ScalarPair(..) => {
37             return cx.type_struct(
38                 &[
39                     layout.scalar_pair_element_gcc_type(cx, 0, false),
40                     layout.scalar_pair_element_gcc_type(cx, 1, false),
41                 ],
42                 false,
43             );
44         }
45         Abi::Uninhabited | Abi::Aggregate { .. } => {}
46     }
47
48     let name = match layout.ty.kind() {
49         // FIXME(eddyb) producing readable type names for trait objects can result
50         // in problematically distinct types due to HRTB and subtyping (see #47638).
51         // ty::Dynamic(..) |
52         ty::Adt(..) | ty::Closure(..) | ty::Foreign(..) | ty::Generator(..) | ty::Str
53             if !cx.sess().fewer_names() =>
54         {
55             let mut name = with_no_trimmed_paths(|| layout.ty.to_string());
56             if let (&ty::Adt(def, _), &Variants::Single { index }) =
57                 (layout.ty.kind(), &layout.variants)
58             {
59                 if def.is_enum() && !def.variants.is_empty() {
60                     write!(&mut name, "::{}", def.variants[index].ident).unwrap();
61                 }
62             }
63             if let (&ty::Generator(_, _, _), &Variants::Single { index }) =
64                 (layout.ty.kind(), &layout.variants)
65             {
66                 write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap();
67             }
68             Some(name)
69         }
70         ty::Adt(..) => {
71             // If `Some` is returned then a named struct is created in LLVM. Name collisions are
72             // avoided by LLVM (with increasing suffixes). If rustc doesn't generate names then that
73             // can improve perf.
74             // FIXME: I don't think that's true for libgccjit.
75             Some(String::new())
76         }
77         _ => None,
78     };
79
80     match layout.fields {
81         FieldsShape::Primitive | FieldsShape::Union(_) => {
82             let fill = cx.type_padding_filler(layout.size, layout.align.abi);
83             let packed = false;
84             match name {
85                 None => cx.type_struct(&[fill], packed),
86                 Some(ref name) => {
87                     let gcc_type = cx.type_named_struct(name);
88                     cx.set_struct_body(gcc_type, &[fill], packed);
89                     gcc_type.as_type()
90                 },
91             }
92         }
93         FieldsShape::Array { count, .. } => cx.type_array(layout.field(cx, 0).gcc_type(cx, true), count),
94         FieldsShape::Arbitrary { .. } =>
95             match name {
96                 None => {
97                     let (gcc_fields, packed) = struct_fields(cx, layout);
98                     cx.type_struct(&gcc_fields, packed)
99                 },
100                 Some(ref name) => {
101                     let gcc_type = cx.type_named_struct(name);
102                     *defer = Some((gcc_type, layout));
103                     gcc_type.as_type()
104                 },
105             },
106     }
107 }
108
109 pub trait LayoutGccExt<'tcx> {
110     fn is_gcc_immediate(&self) -> bool;
111     fn is_gcc_scalar_pair(&self) -> bool;
112     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc>;
113     fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc>;
114     fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc>;
115     fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc>;
116     fn gcc_field_index(&self, index: usize) -> u64;
117     fn pointee_info_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, offset: Size) -> Option<PointeeInfo>;
118 }
119
120 impl<'tcx> LayoutGccExt<'tcx> for TyAndLayout<'tcx> {
121     fn is_gcc_immediate(&self) -> bool {
122         match self.abi {
123             Abi::Scalar(_) | Abi::Vector { .. } => true,
124             Abi::ScalarPair(..) => false,
125             Abi::Uninhabited | Abi::Aggregate { .. } => self.is_zst(),
126         }
127     }
128
129     fn is_gcc_scalar_pair(&self) -> bool {
130         match self.abi {
131             Abi::ScalarPair(..) => true,
132             Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } | Abi::Aggregate { .. } => false,
133         }
134     }
135
136     /// Gets the GCC type corresponding to a Rust type, i.e., `rustc_middle::ty::Ty`.
137     /// The pointee type of the pointer in `PlaceRef` is always this type.
138     /// For sized types, it is also the right LLVM type for an `alloca`
139     /// containing a value of that type, and most immediates (except `bool`).
140     /// Unsized types, however, are represented by a "minimal unit", e.g.
141     /// `[T]` becomes `T`, while `str` and `Trait` turn into `i8` - this
142     /// is useful for indexing slices, as `&[T]`'s data pointer is `T*`.
143     /// If the type is an unsized struct, the regular layout is generated,
144     /// with the inner-most trailing unsized field using the "minimal unit"
145     /// of that field's type - this is useful for taking the address of
146     /// that field and ensuring the struct has the right alignment.
147     fn gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, set_fields: bool) -> Type<'gcc> {
148         if let Abi::Scalar(ref scalar) = self.abi {
149             // Use a different cache for scalars because pointers to DSTs
150             // can be either fat or thin (data pointers of fat pointers).
151             if let Some(&ty) = cx.scalar_types.borrow().get(&self.ty) {
152                 return ty;
153             }
154             let ty =
155                 match *self.ty.kind() {
156                     ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => {
157                         cx.type_ptr_to(cx.layout_of(ty).gcc_type(cx, set_fields))
158                     }
159                     ty::Adt(def, _) if def.is_box() => {
160                         cx.type_ptr_to(cx.layout_of(self.ty.boxed_ty()).gcc_type(cx, true))
161                     }
162                     ty::FnPtr(sig) => cx.fn_ptr_backend_type(&FnAbi::of_fn_ptr(cx, sig, &[])),
163                     _ => self.scalar_gcc_type_at(cx, scalar, Size::ZERO),
164                 };
165             cx.scalar_types.borrow_mut().insert(self.ty, ty);
166             return ty;
167         }
168
169         // Check the cache.
170         let variant_index =
171             match self.variants {
172                 Variants::Single { index } => Some(index),
173                 _ => None,
174             };
175         let cached_type = cx.types.borrow().get(&(self.ty, variant_index)).cloned();
176         if let Some(ty) = cached_type {
177             let type_to_set_fields = cx.types_with_fields_to_set.borrow_mut().remove(&ty);
178             if let Some((struct_type, layout)) = type_to_set_fields {
179                 // Since we might be trying to generate a type containing another type which is not
180                 // completely generated yet, we deferred setting the fields until now.
181                 let (fields, packed) = struct_fields(cx, layout);
182                 cx.set_struct_body(struct_type, &fields, packed);
183             }
184             return ty;
185         }
186
187         //debug!("gcc_type({:#?})", self);
188
189         assert!(!self.ty.has_escaping_bound_vars(), "{:?} has escaping bound vars", self.ty);
190
191         // Make sure lifetimes are erased, to avoid generating distinct LLVM
192         // types for Rust types that only differ in the choice of lifetimes.
193         let normal_ty = cx.tcx.erase_regions(self.ty);
194
195         let mut defer = None;
196         let ty =
197             if self.ty != normal_ty {
198                 let mut layout = cx.layout_of(normal_ty);
199                 if let Some(v) = variant_index {
200                     layout = layout.for_variant(cx, v);
201                 }
202                 layout.gcc_type(cx, true)
203             }
204             else {
205                 uncached_gcc_type(cx, *self, &mut defer)
206             };
207         //debug!("--> mapped {:#?} to ty={:?}", self, ty);
208
209         cx.types.borrow_mut().insert((self.ty, variant_index), ty);
210
211         if let Some((ty, layout)) = defer {
212             //TODO: do we still need this conditions and the set_fields parameter?
213             //if set_fields {
214                 let (fields, packed) = struct_fields(cx, layout);
215                 cx.set_struct_body(ty, &fields, packed);
216             /*}
217             else {
218                 // Since we might be trying to generate a type containing another type which is not
219                 // completely generated yet, we don't set the fields right now, but we save the
220                 // type to set the fields later.
221                 cx.types_with_fields_to_set.borrow_mut().insert(ty.as_type(), (ty, layout));
222             }*/
223         }
224
225         ty
226     }
227
228     fn immediate_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>) -> Type<'gcc> {
229         if let Abi::Scalar(ref scalar) = self.abi {
230             if scalar.is_bool() {
231                 return cx.type_i1();
232             }
233         }
234         self.gcc_type(cx, true)
235     }
236
237     fn scalar_gcc_type_at<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, scalar: &abi::Scalar, offset: Size) -> Type<'gcc> {
238         match scalar.value {
239             Int(i, true) => cx.type_from_integer(i),
240             Int(i, false) => cx.type_from_unsigned_integer(i),
241             F32 => cx.type_f32(),
242             F64 => cx.type_f64(),
243             Pointer => {
244                 // If we know the alignment, pick something better than i8.
245                 let pointee =
246                     if let Some(pointee) = self.pointee_info_at(cx, offset) {
247                         cx.type_pointee_for_align(pointee.align)
248                     }
249                     else {
250                         cx.type_i8()
251                     };
252                 cx.type_ptr_to(pointee)
253             }
254         }
255     }
256
257     fn scalar_pair_element_gcc_type<'gcc>(&self, cx: &CodegenCx<'gcc, 'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
258         // TODO: remove llvm hack:
259         // HACK(eddyb) special-case fat pointers until LLVM removes
260         // pointee types, to avoid bitcasting every `OperandRef::deref`.
261         match self.ty.kind() {
262             ty::Ref(..) | ty::RawPtr(_) => {
263                 return self.field(cx, index).gcc_type(cx, true);
264             }
265             ty::Adt(def, _) if def.is_box() => {
266                 let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
267                 return cx.layout_of(ptr_ty).scalar_pair_element_gcc_type(cx, index, immediate);
268             }
269             _ => {}
270         }
271
272         let (a, b) = match self.abi {
273             Abi::ScalarPair(ref a, ref b) => (a, b),
274             _ => bug!("TyAndLayout::scalar_pair_element_llty({:?}): not applicable", self),
275         };
276         let scalar = [a, b][index];
277
278         // Make sure to return the same type `immediate_gcc_type` would when
279         // dealing with an immediate pair.  This means that `(bool, bool)` is
280         // effectively represented as `{i8, i8}` in memory and two `i1`s as an
281         // immediate, just like `bool` is typically `i8` in memory and only `i1`
282         // when immediate.  We need to load/store `bool` as `i8` to avoid
283         // crippling LLVM optimizations or triggering other LLVM bugs with `i1`.
284         // TODO: this bugs certainly don't happen in this case since the bool type is used instead of i1.
285         if /*immediate &&*/ scalar.is_bool() {
286             return cx.type_i1();
287         }
288
289         let offset =
290             if index == 0 {
291                 Size::ZERO
292             }
293             else {
294                 a.value.size(cx).align_to(b.value.align(cx).abi)
295             };
296         self.scalar_gcc_type_at(cx, scalar, offset)
297     }
298
299     fn gcc_field_index(&self, index: usize) -> u64 {
300         match self.abi {
301             Abi::Scalar(_) | Abi::ScalarPair(..) => {
302                 bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
303             }
304             _ => {}
305         }
306         match self.fields {
307             FieldsShape::Primitive | FieldsShape::Union(_) => {
308                 bug!("TyAndLayout::gcc_field_index({:?}): not applicable", self)
309             }
310
311             FieldsShape::Array { .. } => index as u64,
312
313             FieldsShape::Arbitrary { .. } => 1 + (self.fields.memory_index(index) as u64) * 2,
314         }
315     }
316
317     fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option<PointeeInfo> {
318         if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) {
319             return pointee;
320         }
321
322         let result = Ty::pointee_info_at(*self, cx, offset);
323
324         cx.pointee_infos.borrow_mut().insert((self.ty, offset), result);
325         result
326     }
327 }
328
329 impl<'gcc, 'tcx> LayoutTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
330     fn backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
331         layout.gcc_type(self, true)
332     }
333
334     fn immediate_backend_type(&self, layout: TyAndLayout<'tcx>) -> Type<'gcc> {
335         layout.immediate_gcc_type(self)
336     }
337
338     fn is_backend_immediate(&self, layout: TyAndLayout<'tcx>) -> bool {
339         layout.is_gcc_immediate()
340     }
341
342     fn is_backend_scalar_pair(&self, layout: TyAndLayout<'tcx>) -> bool {
343         layout.is_gcc_scalar_pair()
344     }
345
346     fn backend_field_index(&self, layout: TyAndLayout<'tcx>, index: usize) -> u64 {
347         layout.gcc_field_index(index)
348     }
349
350     fn scalar_pair_element_backend_type(&self, layout: TyAndLayout<'tcx>, index: usize, immediate: bool) -> Type<'gcc> {
351         layout.scalar_pair_element_gcc_type(self, index, immediate)
352     }
353
354     fn cast_backend_type(&self, ty: &CastTarget) -> Type<'gcc> {
355         ty.gcc_type(self)
356     }
357
358     fn fn_ptr_backend_type(&self, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
359         fn_abi.ptr_to_gcc_type(self)
360     }
361
362     fn reg_backend_type(&self, _ty: &Reg) -> Type<'gcc> {
363         unimplemented!();
364         //ty.gcc_type(self)
365     }
366
367     fn fn_decl_backend_type(&self, _fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Type<'gcc> {
368         // FIXME: return correct type.
369         self.type_void()
370         //fn_abi.gcc_type(self)
371     }
372 }