1 use std::convert::TryInto;
3 use gccjit::{RValue, Struct, Type};
4 use rustc_codegen_ssa::traits::{BaseTypeMethods, DerivedTypeMethods};
5 use rustc_codegen_ssa::common::TypeKind;
7 use rustc_middle::ty::layout::TyAndLayout;
8 use rustc_target::abi::{AddressSpace, Align, Integer, Size};
10 use crate::common::TypeReflection;
11 use crate::context::CodegenCx;
12 use crate::type_of::LayoutGccExt;
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;
24 _ => panic!("unexpected num_bits: {}", num_bits),
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.
33 /*pub fn type_bool(&self) -> Type<'gcc> {
37 pub fn type_void(&self) -> Type<'gcc> {
38 self.context.new_type::<()>()
41 pub fn type_size_t(&self) -> Type<'gcc> {
42 self.context.new_type::<usize>()
45 pub fn type_u8(&self) -> Type<'gcc> {
49 pub fn type_u16(&self) -> Type<'gcc> {
53 pub fn type_u32(&self) -> Type<'gcc> {
57 pub fn type_u64(&self) -> Type<'gcc> {
61 pub fn type_u128(&self) -> Type<'gcc> {
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)
71 /*pub fn type_int_from_ty(&self, t: ty::IntTy) -> Type<'gcc> {
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(),
82 pub fn type_uint_from_ty(&self, t: ty::UintTy) -> Type<'gcc> {
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(),
93 pub fn type_float_from_ty(&self, t: ty::FloatTy) -> Type<'gcc> {
95 ty::FloatTy::F32 => self.type_f32(),
96 ty::FloatTy::F64 => self.type_f64(),
100 pub fn type_vector(&self, ty: Type<'gcc>, len: u64) -> Type<'gcc> {
101 self.context.new_vector_type(ty, len)
105 impl<'gcc, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'gcc, 'tcx> {
106 fn type_i1(&self) -> Type<'gcc> {
110 fn type_i8(&self) -> Type<'gcc> {
114 fn type_i16(&self) -> Type<'gcc> {
118 fn type_i32(&self) -> Type<'gcc> {
122 fn type_i64(&self) -> Type<'gcc> {
126 fn type_i128(&self) -> Type<'gcc> {
130 fn type_isize(&self) -> Type<'gcc> {
134 fn type_f32(&self) -> Type<'gcc> {
135 self.context.new_type::<f32>()
138 fn type_f64(&self) -> Type<'gcc> {
139 self.context.new_type::<f64>()
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)
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) {
151 let fields: Vec<_> = fields.iter().enumerate()
152 .map(|(index, field)| self.context.new_field(None, *field, &format!("field{}_TODO", index)))
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);
162 fn type_kind(&self, typ: Type<'gcc>) -> TypeKind {
163 if typ.is_integral() {
166 else if typ.is_vector().is_some() {
175 fn type_ptr_to(&self, ty: Type<'gcc>) -> Type<'gcc> {
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"
183 fn type_ptr_to_ext(&self, ty: Type<'gcc>, _address_space: AddressSpace) -> Type<'gcc> {
184 // TODO: use address_space
188 fn element_type(&self, ty: Type<'gcc>) -> Type<'gcc> {
189 if let Some(typ) = ty.is_array() {
192 else if let Some(vector_type) = ty.is_vector() {
193 vector_type.get_element_type()
195 else if let Some(typ) = ty.get_pointee() {
203 fn vector_length(&self, _ty: Type<'gcc>) -> usize {
205 //unsafe { llvm::LLVMGetVectorSize(ty) as usize }
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>();
218 panic!("Cannot get width of float type {:?}", typ);
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"),
230 fn int_width(&self, typ: Type<'gcc>) -> u64 {
231 if typ.is_i8(self) || typ.is_u8(self) {
234 else if typ.is_i16(self) || typ.is_u16(self) {
237 else if typ.is_i32(self) || typ.is_u32(self) {
240 else if typ.is_i64(self) || typ.is_u64(self) {
243 else if typ.is_i128(self) || typ.is_u128(self) {
247 panic!("Cannot get width of int type {:?}", typ);
251 fn val_ty(&self, value: RValue<'gcc>) -> Type<'gcc> {
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)
265 pub fn set_struct_body(&self, typ: Struct<'gcc>, fields: &[Type<'gcc>], _packed: bool) {
267 let fields: Vec<_> = fields.iter().enumerate()
268 .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
270 typ.set_fields(None, &fields);
273 /*fn type_struct(&self, fields: &[Type<'gcc>], packed: bool) -> Type<'gcc> {
275 let fields: Vec<_> = fields.iter().enumerate()
276 .map(|(index, field)| self.context.new_field(None, *field, &format!("field_{}", index)))
278 return self.context.new_struct_type(None, "unnamedStruct", &fields).as_type();
281 pub fn type_named_struct(&self, name: &str) -> Struct<'gcc> {
282 self.context.new_opaque_struct_type(None, name)
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
291 // FIXME: fix gccjit API.
296 // NOTE: see note above. Some other test uses usize::MAX.
301 let len: i32 = len.try_into().expect("array len");
303 self.context.new_array_type(None, ty, len)
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();
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;
323 "struct_fields: {}: {:?} offset: {:?} target_offset: {:?} \
324 effective_field_align: {}",
329 effective_field_align.bytes()
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);
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;
342 if !layout.is_unsized() && field_count > 0 {
343 if offset > layout.size {
344 bug!("layout: {:#?} stride: {:?} offset: {:?}", layout, layout.size, offset);
346 let padding = layout.size - offset;
347 let padding_align = prev_effective_align;
348 assert_eq!(offset.align_to(padding_align) + padding, layout.size);
350 "struct_fields: pad_bytes: {:?} offset: {:?} stride: {:?}",
351 padding, offset, layout.size
353 result.push(cx.type_padding_filler(padding, padding_align));
354 assert_eq!(result.len(), 1 + field_count * 2);
356 //debug!("struct_fields: offset: {:?} stride: {:?}", offset, layout.size);