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