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