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