]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/type_.rs
Generalized base::unsize_thin_ptr
[rust.git] / src / librustc_codegen_llvm / type_.rs
1 // Copyright 2013 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 #![allow(non_upper_case_globals)]
12
13 pub use llvm::Type;
14
15 use llvm;
16 use llvm::{Bool, False, True};
17 use context::CodegenCx;
18 use interfaces::*;
19 use value::Value;
20
21
22 use syntax::ast;
23 use rustc::ty::layout::{self, Align, Size, HasTyCtxt};
24 use rustc::util::nodemap::FxHashMap;
25 use rustc::ty::{self, Ty};
26 use rustc::ty::layout::TyLayout;
27 use rustc_data_structures::small_c_str::SmallCStr;
28 use common::{self, TypeKind};
29 use type_of::LayoutLlvmExt;
30
31 use std::fmt;
32 use std::cell::RefCell;
33
34 use libc::c_uint;
35
36 impl PartialEq for Type {
37     fn eq(&self, other: &Self) -> bool {
38         self as *const _ == other as *const _
39     }
40 }
41
42 impl fmt::Debug for Type {
43     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
44         f.write_str(&llvm::build_string(|s| unsafe {
45             llvm::LLVMRustWriteTypeToString(self, s);
46         }).expect("non-UTF8 type description from LLVM"))
47     }
48 }
49
50 impl BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
51     fn type_void(&self) -> &'ll Type {
52         unsafe {
53             llvm::LLVMVoidTypeInContext(self.llcx)
54         }
55     }
56
57     fn type_metadata(&self) -> &'ll Type {
58         unsafe {
59             llvm::LLVMRustMetadataTypeInContext(self.llcx)
60         }
61     }
62
63     fn type_i1(&self) -> &'ll Type {
64         unsafe {
65             llvm::LLVMInt1TypeInContext(self.llcx)
66         }
67     }
68
69     fn type_i8(&self) -> &'ll Type {
70         unsafe {
71             llvm::LLVMInt8TypeInContext(self.llcx)
72         }
73     }
74
75
76     fn type_i16(&self) -> &'ll Type {
77         unsafe {
78
79             llvm::LLVMInt16TypeInContext(self.llcx)
80         }
81     }
82
83     fn type_i32(&self) -> &'ll Type {
84         unsafe {
85             llvm::LLVMInt32TypeInContext(self.llcx)
86         }
87     }
88
89     fn type_i64(&self) -> &'ll Type {
90         unsafe {
91             llvm::LLVMInt64TypeInContext(self.llcx)
92         }
93     }
94
95     fn type_i128(&self) -> &'ll Type {
96         unsafe {
97             llvm::LLVMIntTypeInContext(self.llcx, 128)
98         }
99     }
100
101     // Creates an integer type with the given number of bits, e.g. i24
102     fn type_ix(&self, num_bits: u64) -> &'ll Type {
103         unsafe {
104             llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint)
105         }
106     }
107
108     fn type_f32(&self) -> &'ll Type {
109         unsafe {
110             llvm::LLVMFloatTypeInContext(self.llcx)
111         }
112     }
113
114     fn type_f64(&self) -> &'ll Type {
115         unsafe {
116             llvm::LLVMDoubleTypeInContext(self.llcx)
117         }
118     }
119
120     fn type_x86_mmx(&self) -> &'ll Type {
121         unsafe {
122             llvm::LLVMX86MMXTypeInContext(self.llcx)
123         }
124     }
125
126     fn type_func(
127         &self,
128         args: &[&'ll Type],
129         ret: &'ll Type
130     ) -> &'ll Type {
131         unsafe {
132             llvm::LLVMFunctionType(ret, args.as_ptr(),
133                                    args.len() as c_uint, False)
134         }
135     }
136
137     fn type_variadic_func(
138         &self,
139         args: &[&'ll Type],
140         ret: &'ll Type
141     ) -> &'ll Type {
142         unsafe {
143             llvm::LLVMFunctionType(ret, args.as_ptr(),
144                                    args.len() as c_uint, True)
145         }
146     }
147
148     fn type_struct(
149         &self,
150         els: &[&'ll Type],
151         packed: bool
152     ) -> &'ll Type {
153         unsafe {
154             llvm::LLVMStructTypeInContext(self.llcx, els.as_ptr(),
155                                           els.len() as c_uint,
156                                           packed as Bool)
157         }
158     }
159
160     fn type_named_struct(&self, name: &str) -> &'ll Type {
161         let name = SmallCStr::new(name);
162         unsafe {
163             llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr())
164         }
165     }
166
167
168     fn type_array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
169         unsafe {
170             llvm::LLVMRustArrayType(ty, len)
171         }
172     }
173
174     fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
175         unsafe {
176             llvm::LLVMVectorType(ty, len as c_uint)
177         }
178     }
179
180     fn type_kind(&self, ty: &'ll Type) -> TypeKind {
181         unsafe {
182             llvm::LLVMRustGetTypeKind(ty).to_generic()
183         }
184     }
185
186     fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
187         unsafe {
188             llvm::LLVMStructSetBody(ty, els.as_ptr(),
189                                     els.len() as c_uint, packed as Bool)
190         }
191     }
192
193     fn type_ptr_to(&self, ty: &'ll Type) -> &'ll Type {
194         assert_ne!(self.type_kind(ty), TypeKind::Function,
195                    "don't call ptr_to on function types, use ptr_to_llvm_type on FnType instead");
196         ty.ptr_to()
197     }
198
199     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
200         unsafe {
201             llvm::LLVMGetElementType(ty)
202         }
203     }
204
205     /// Return the number of elements in `self` if it is a LLVM vector type.
206     fn vector_length(&self, ty: &'ll Type) -> usize {
207         unsafe {
208             llvm::LLVMGetVectorSize(ty) as usize
209         }
210     }
211
212     fn func_params_types(&self, ty: &'ll Type) -> Vec<&'ll Type> {
213         unsafe {
214             let n_args = llvm::LLVMCountParamTypes(ty) as usize;
215             let mut args = Vec::with_capacity(n_args);
216             llvm::LLVMGetParamTypes(ty, args.as_mut_ptr());
217             args.set_len(n_args);
218             args
219         }
220     }
221
222     fn float_width(&self, ty: &'ll Type) -> usize {
223         match self.type_kind(ty) {
224             TypeKind::Float => 32,
225             TypeKind::Double => 64,
226             TypeKind::X86_FP80 => 80,
227             TypeKind::FP128 | TypeKind::PPc_FP128 => 128,
228             _ => bug!("llvm_float_width called on a non-float type")
229         }
230     }
231
232     /// Retrieve the bit width of the integer type `self`.
233     fn int_width(&self, ty: &'ll Type) -> u64 {
234         unsafe {
235             llvm::LLVMGetIntTypeWidth(ty) as u64
236         }
237     }
238
239     fn val_ty(&self, v: &'ll Value) -> &'ll Type {
240         common::val_ty(v)
241     }
242
243     fn scalar_lltypes(&self) -> &RefCell<FxHashMap<Ty<'tcx>, Self::Type>> {
244         &self.scalar_lltypes
245     }
246 }
247
248 impl Type {
249     pub fn i8_llcx(llcx: &llvm::Context) -> &Type {
250         unsafe {
251             llvm::LLVMInt8TypeInContext(llcx)
252         }
253     }
254
255     // Creates an integer type with the given number of bits, e.g. i24
256     pub fn ix_llcx(
257         llcx: &llvm::Context,
258         num_bits: u64
259     ) -> &Type {
260         unsafe {
261             llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint)
262         }
263     }
264
265     pub fn i8p_llcx(llcx: &'ll llvm::Context) -> &'ll Type {
266         Type::i8_llcx(llcx).ptr_to()
267     }
268
269     fn ptr_to(&self) -> &Type {
270         unsafe {
271             llvm::LLVMPointerType(&self, 0)
272         }
273     }
274 }
275
276 impl DerivedTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
277     fn type_bool(&self) -> &'ll Type {
278         self.type_i8()
279     }
280
281     fn type_i8p(&self) -> &'ll Type {
282         self.type_ptr_to(self.type_i8())
283     }
284
285     fn type_isize(&self) -> &'ll Type {
286         self.isize_ty
287     }
288
289     fn type_int(&self) -> &'ll Type {
290         match &self.sess().target.target.target_c_int_width[..] {
291             "16" => self.type_i16(),
292             "32" => self.type_i32(),
293             "64" => self.type_i64(),
294             width => bug!("Unsupported target_c_int_width: {}", width),
295         }
296     }
297
298     fn type_int_from_ty(
299         &self,
300         t: ast::IntTy
301     ) -> &'ll Type {
302         match t {
303             ast::IntTy::Isize => self.isize_ty,
304             ast::IntTy::I8 => self.type_i8(),
305             ast::IntTy::I16 => self.type_i16(),
306             ast::IntTy::I32 => self.type_i32(),
307             ast::IntTy::I64 => self.type_i64(),
308             ast::IntTy::I128 => self.type_i128(),
309         }
310     }
311
312     fn type_uint_from_ty(
313         &self,
314         t: ast::UintTy
315     ) -> &'ll Type {
316         match t {
317             ast::UintTy::Usize => self.isize_ty,
318             ast::UintTy::U8 => self.type_i8(),
319             ast::UintTy::U16 => self.type_i16(),
320             ast::UintTy::U32 => self.type_i32(),
321             ast::UintTy::U64 => self.type_i64(),
322             ast::UintTy::U128 => self.type_i128(),
323         }
324     }
325
326     fn type_float_from_ty(
327         &self,
328         t: ast::FloatTy
329     ) -> &'ll Type {
330         match t {
331             ast::FloatTy::F32 => self.type_f32(),
332             ast::FloatTy::F64 => self.type_f64(),
333         }
334     }
335
336     fn type_from_integer(&self, i: layout::Integer) -> &'ll Type {
337         use rustc::ty::layout::Integer::*;
338         match i {
339             I8 => self.type_i8(),
340             I16 => self.type_i16(),
341             I32 => self.type_i32(),
342             I64 => self.type_i64(),
343             I128 => self.type_i128(),
344         }
345     }
346
347     /// Return a LLVM type that has at most the required alignment,
348     /// as a conservative approximation for unknown pointee types.
349     fn type_pointee_for_abi_align(&self, align: Align) -> &'ll Type {
350         // FIXME(eddyb) We could find a better approximation if ity.align < align.
351         let ity = layout::Integer::approximate_abi_align(self, align);
352         self.type_from_integer(ity)
353     }
354
355     /// Return a LLVM type that has at most the required alignment,
356     /// and exactly the required size, as a best-effort padding array.
357     fn type_padding_filler(
358         &self,
359         size: Size,
360         align: Align
361     ) -> &'ll Type {
362         let unit = layout::Integer::approximate_abi_align(self, align);
363         let size = size.bytes();
364         let unit_size = unit.size().bytes();
365         assert_eq!(size % unit_size, 0);
366         self.type_array(self.type_from_integer(unit), size / unit_size)
367     }
368
369     fn type_needs_drop(&self, ty: Ty<'tcx>) -> bool {
370         common::type_needs_drop(self.tcx(), ty)
371     }
372
373     fn type_is_sized(&self, ty: Ty<'tcx>) -> bool {
374         common::type_is_sized(self.tcx(), ty)
375     }
376
377     fn type_is_freeze(&self, ty: Ty<'tcx>) -> bool {
378         common::type_is_freeze(self.tcx(), ty)
379     }
380
381     fn type_has_metadata(&self, ty: Ty<'tcx>) -> bool {
382         use syntax_pos::DUMMY_SP;
383         if ty.is_sized(self.tcx().at(DUMMY_SP), ty::ParamEnv::reveal_all()) {
384             return false;
385         }
386
387         let tail = self.tcx().struct_tail(ty);
388         match tail.sty {
389             ty::Foreign(..) => false,
390             ty::Str | ty::Slice(..) | ty::Dynamic(..) => true,
391             _ => bug!("unexpected unsized tail: {:?}", tail.sty),
392         }
393     }
394 }
395
396 impl LayoutTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> {
397     fn backend_type(&self, ty: &TyLayout<'tcx>) -> &'ll Type {
398         ty.llvm_type(&self)
399     }
400     fn scalar_pair_element_backend_type<'a>(
401         &self,
402         ty: &TyLayout<'tcx>,
403         index: usize,
404         immediate: bool
405     ) -> &'ll Type {
406         ty.scalar_pair_element_llvm_type(&self, index, immediate)
407     }
408 }