]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/type_.rs
Replace `0 as *const/mut T` with `ptr::null/null_mut()`
[rust.git] / src / librustc_trans / trans / 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 use llvm;
14 use llvm::{TypeRef, Bool, False, True, TypeKind, ValueRef};
15 use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
16
17 use trans::context::CrateContext;
18 use util::nodemap::FnvHashMap;
19
20 use syntax::ast;
21
22 use std::ffi::CString;
23 use std::mem;
24 use std::ptr;
25 use std::cell::RefCell;
26 use std::iter::repeat;
27
28 use libc::c_uint;
29
30 #[derive(Clone, Copy, PartialEq, Show)]
31 #[repr(C)]
32 pub struct Type {
33     rf: TypeRef
34 }
35
36 macro_rules! ty {
37     ($e:expr) => ( Type::from_ref(unsafe { $e }))
38 }
39
40 /// Wrapper for LLVM TypeRef
41 impl Type {
42     #[inline(always)]
43     pub fn from_ref(r: TypeRef) -> Type {
44         Type {
45             rf: r
46         }
47     }
48
49     #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
50     pub fn to_ref(&self) -> TypeRef {
51         self.rf
52     }
53
54     pub fn void(ccx: &CrateContext) -> Type {
55         ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
56     }
57
58     pub fn nil(ccx: &CrateContext) -> Type {
59         Type::empty_struct(ccx)
60     }
61
62     pub fn metadata(ccx: &CrateContext) -> Type {
63         ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx()))
64     }
65
66     pub fn i1(ccx: &CrateContext) -> Type {
67         ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
68     }
69
70     pub fn i8(ccx: &CrateContext) -> Type {
71         ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
72     }
73
74     pub fn i16(ccx: &CrateContext) -> Type {
75         ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
76     }
77
78     pub fn i32(ccx: &CrateContext) -> Type {
79         ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
80     }
81
82     pub fn i64(ccx: &CrateContext) -> Type {
83         ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
84     }
85
86     // Creates an integer type with the given number of bits, e.g. i24
87     pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
88         ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
89     }
90
91     pub fn f32(ccx: &CrateContext) -> Type {
92         ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
93     }
94
95     pub fn f64(ccx: &CrateContext) -> Type {
96         ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
97     }
98
99     pub fn bool(ccx: &CrateContext) -> Type {
100         Type::i8(ccx)
101     }
102
103     pub fn char(ccx: &CrateContext) -> Type {
104         Type::i32(ccx)
105     }
106
107     pub fn i8p(ccx: &CrateContext) -> Type {
108         Type::i8(ccx).ptr_to()
109     }
110
111     pub fn int(ccx: &CrateContext) -> Type {
112         match &ccx.tcx().sess.target.target.target_pointer_width[] {
113             "32" => Type::i32(ccx),
114             "64" => Type::i64(ccx),
115             tws => panic!("Unsupported target word size for int: {}", tws),
116         }
117     }
118
119     pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
120         match t {
121             ast::TyIs(_) => ccx.int_type(),
122             ast::TyI8 => Type::i8(ccx),
123             ast::TyI16 => Type::i16(ccx),
124             ast::TyI32 => Type::i32(ccx),
125             ast::TyI64 => Type::i64(ccx)
126         }
127     }
128
129     pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
130         match t {
131             ast::TyUs(_) => ccx.int_type(),
132             ast::TyU8 => Type::i8(ccx),
133             ast::TyU16 => Type::i16(ccx),
134             ast::TyU32 => Type::i32(ccx),
135             ast::TyU64 => Type::i64(ccx)
136         }
137     }
138
139     pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
140         match t {
141             ast::TyF32 => Type::f32(ccx),
142             ast::TyF64 => Type::f64(ccx),
143         }
144     }
145
146     pub fn func(args: &[Type], ret: &Type) -> Type {
147         let vec : &[TypeRef] = unsafe { mem::transmute(args) };
148         ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
149                                    args.len() as c_uint, False))
150     }
151
152     pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
153         let vec : &[TypeRef] = unsafe { mem::transmute(args) };
154         ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
155                                    args.len() as c_uint, True))
156     }
157
158     pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
159         let els : &[TypeRef] = unsafe { mem::transmute(els) };
160         ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
161                                           els.len() as c_uint,
162                                           packed as Bool))
163     }
164
165     pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
166         let name = CString::from_slice(name.as_bytes());
167         ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
168     }
169
170     pub fn empty_struct(ccx: &CrateContext) -> Type {
171         Type::struct_(ccx, &[], false)
172     }
173
174     pub fn vtable(ccx: &CrateContext) -> Type {
175         Type::array(&Type::i8p(ccx).ptr_to(), 1)
176     }
177
178     pub fn generic_glue_fn(cx: &CrateContext) -> Type {
179         match cx.tn().find_type("glue_fn") {
180             Some(ty) => return ty,
181             None => ()
182         }
183
184         let ty = Type::glue_fn(cx, Type::i8p(cx));
185         cx.tn().associate_type("glue_fn", &ty);
186
187         ty
188     }
189
190     pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
191         Type::func(&[t], &Type::void(ccx))
192     }
193
194     pub fn tydesc(ccx: &CrateContext, str_slice_ty: Type) -> Type {
195         let mut tydesc = Type::named_struct(ccx, "tydesc");
196         let glue_fn_ty = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to();
197
198         let int_ty = Type::int(ccx);
199
200         // Must mirror:
201         //
202         // std::unstable::intrinsics::TyDesc
203
204         let elems = [int_ty,     // size
205                      int_ty,     // align
206                      glue_fn_ty, // drop
207                      str_slice_ty]; // name
208         tydesc.set_struct_body(&elems, false);
209
210         tydesc
211     }
212
213     pub fn array(ty: &Type, len: u64) -> Type {
214         ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
215     }
216
217     pub fn vector(ty: &Type, len: u64) -> Type {
218         ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
219     }
220
221     pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
222         Type::struct_(ccx,
223             &[Type::array(ty, 0), Type::int(ccx)],
224         false)
225     }
226
227     pub fn opaque_vec(ccx: &CrateContext) -> Type {
228         Type::vec(ccx, &Type::i8(ccx))
229     }
230
231     // The box pointed to by @T.
232     pub fn at_box(ccx: &CrateContext, ty: Type) -> Type {
233         Type::struct_(ccx, &[
234             ccx.int_type(), Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to(),
235             Type::i8p(ccx), Type::i8p(ccx), ty
236         ], false)
237     }
238
239     pub fn vtable_ptr(ccx: &CrateContext) -> Type {
240         Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
241     }
242
243     pub fn opaque_trait(ccx: &CrateContext) -> Type {
244         Type::struct_(ccx, &[Type::opaque_trait_data(ccx).ptr_to(), Type::vtable_ptr(ccx)], false)
245     }
246
247     pub fn opaque_trait_data(ccx: &CrateContext) -> Type {
248         Type::i8(ccx)
249     }
250
251     pub fn kind(&self) -> TypeKind {
252         unsafe {
253             llvm::LLVMGetTypeKind(self.to_ref())
254         }
255     }
256
257     pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
258         unsafe {
259             let vec : &[TypeRef] = mem::transmute(els);
260             llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
261                                     els.len() as c_uint, packed as Bool)
262         }
263     }
264
265     pub fn ptr_to(&self) -> Type {
266         ty!(llvm::LLVMPointerType(self.to_ref(), 0))
267     }
268
269     pub fn is_aggregate(&self) -> bool {
270         match self.kind() {
271             TypeKind::Struct | TypeKind::Array => true,
272             _ =>  false
273         }
274     }
275
276     pub fn is_packed(&self) -> bool {
277         unsafe {
278             llvm::LLVMIsPackedStruct(self.to_ref()) == True
279         }
280     }
281
282     pub fn element_type(&self) -> Type {
283         unsafe {
284             Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
285         }
286     }
287
288     pub fn array_length(&self) -> uint {
289         unsafe {
290             llvm::LLVMGetArrayLength(self.to_ref()) as uint
291         }
292     }
293
294     pub fn field_types(&self) -> Vec<Type> {
295         unsafe {
296             let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
297             if n_elts == 0 {
298                 return Vec::new();
299             }
300             let mut elts: Vec<_> = repeat(Type { rf: ptr::null_mut() }).take(n_elts).collect();
301             llvm::LLVMGetStructElementTypes(self.to_ref(),
302                                             elts.as_mut_ptr() as *mut TypeRef);
303             elts
304         }
305     }
306
307     pub fn return_type(&self) -> Type {
308         ty!(llvm::LLVMGetReturnType(self.to_ref()))
309     }
310
311     pub fn func_params(&self) -> Vec<Type> {
312         unsafe {
313             let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
314             let mut args: Vec<_> = repeat(Type { rf: ptr::null_mut() }).take(n_args).collect();
315             llvm::LLVMGetParamTypes(self.to_ref(),
316                                     args.as_mut_ptr() as *mut TypeRef);
317             args
318         }
319     }
320
321     pub fn float_width(&self) -> uint {
322         match self.kind() {
323             Float => 32,
324             Double => 64,
325             X86_FP80 => 80,
326             FP128 | PPC_FP128 => 128,
327             _ => panic!("llvm_float_width called on a non-float type")
328         }
329     }
330 }
331
332
333 /* Memory-managed object interface to type handles. */
334
335 pub struct TypeNames {
336     named_types: RefCell<FnvHashMap<String, TypeRef>>,
337 }
338
339 impl TypeNames {
340     pub fn new() -> TypeNames {
341         TypeNames {
342             named_types: RefCell::new(FnvHashMap::new())
343         }
344     }
345
346     pub fn associate_type(&self, s: &str, t: &Type) {
347         assert!(self.named_types.borrow_mut().insert(s.to_string(),
348                                                      t.to_ref()).is_none());
349     }
350
351     pub fn find_type(&self, s: &str) -> Option<Type> {
352         self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
353     }
354
355     pub fn type_to_string(&self, ty: Type) -> String {
356         llvm::build_string(|s| unsafe {
357                 llvm::LLVMWriteTypeToString(ty.to_ref(), s);
358             }).expect("non-UTF8 type description from LLVM")
359     }
360
361     pub fn types_to_str(&self, tys: &[Type]) -> String {
362         let strs: Vec<String> = tys.iter().map(|t| self.type_to_string(*t)).collect();
363         format!("[{}]", strs.connect(","))
364     }
365
366     pub fn val_to_string(&self, val: ValueRef) -> String {
367         llvm::build_string(|s| unsafe {
368                 llvm::LLVMWriteValueToString(val, s);
369             }).expect("nun-UTF8 value description from LLVM")
370     }
371 }