]> git.lizzy.rs Git - rust.git/blob - src/librustc_trans/trans/type_.rs
e0df6ec35c2f9febb252d249d9763b6a46126e62
[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 rustc_front::hir;
21
22 use std::ffi::CString;
23 use std::mem;
24 use std::ptr;
25 use std::cell::RefCell;
26
27 use libc::c_uint;
28
29 #[derive(Clone, Copy, PartialEq, Debug)]
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 to_string(self: Type) -> String {
54         llvm::build_string(|s| unsafe {
55             llvm::LLVMWriteTypeToString(self.to_ref(), s);
56         }).expect("non-UTF8 type description from LLVM")
57     }
58
59     pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
60         unsafe { mem::transmute(slice) }
61     }
62
63     pub fn void(ccx: &CrateContext) -> Type {
64         ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
65     }
66
67     pub fn nil(ccx: &CrateContext) -> Type {
68         Type::empty_struct(ccx)
69     }
70
71     pub fn metadata(ccx: &CrateContext) -> Type {
72         ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx()))
73     }
74
75     pub fn i1(ccx: &CrateContext) -> Type {
76         ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
77     }
78
79     pub fn i8(ccx: &CrateContext) -> Type {
80         ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
81     }
82
83     pub fn i16(ccx: &CrateContext) -> Type {
84         ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
85     }
86
87     pub fn i32(ccx: &CrateContext) -> Type {
88         ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
89     }
90
91     pub fn i64(ccx: &CrateContext) -> Type {
92         ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
93     }
94
95     // Creates an integer type with the given number of bits, e.g. i24
96     pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
97         ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
98     }
99
100     pub fn f32(ccx: &CrateContext) -> Type {
101         ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
102     }
103
104     pub fn f64(ccx: &CrateContext) -> Type {
105         ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
106     }
107
108     pub fn bool(ccx: &CrateContext) -> Type {
109         Type::i8(ccx)
110     }
111
112     pub fn char(ccx: &CrateContext) -> Type {
113         Type::i32(ccx)
114     }
115
116     pub fn i8p(ccx: &CrateContext) -> Type {
117         Type::i8(ccx).ptr_to()
118     }
119
120     pub fn int(ccx: &CrateContext) -> Type {
121         match &ccx.tcx().sess.target.target.target_pointer_width[..] {
122             "32" => Type::i32(ccx),
123             "64" => Type::i64(ccx),
124             tws => panic!("Unsupported target word size for int: {}", tws),
125         }
126     }
127
128     pub fn int_from_ty(ccx: &CrateContext, t: hir::IntTy) -> Type {
129         match t {
130             hir::TyIs => ccx.int_type(),
131             hir::TyI8 => Type::i8(ccx),
132             hir::TyI16 => Type::i16(ccx),
133             hir::TyI32 => Type::i32(ccx),
134             hir::TyI64 => Type::i64(ccx)
135         }
136     }
137
138     pub fn uint_from_ty(ccx: &CrateContext, t: hir::UintTy) -> Type {
139         match t {
140             hir::TyUs => ccx.int_type(),
141             hir::TyU8 => Type::i8(ccx),
142             hir::TyU16 => Type::i16(ccx),
143             hir::TyU32 => Type::i32(ccx),
144             hir::TyU64 => Type::i64(ccx)
145         }
146     }
147
148     pub fn float_from_ty(ccx: &CrateContext, t: hir::FloatTy) -> Type {
149         match t {
150             hir::TyF32 => Type::f32(ccx),
151             hir::TyF64 => Type::f64(ccx),
152         }
153     }
154
155     pub fn func(args: &[Type], ret: &Type) -> Type {
156         let slice: &[TypeRef] = Type::to_ref_slice(args);
157         ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
158                                    args.len() as c_uint, False))
159     }
160
161     pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
162         let slice: &[TypeRef] = Type::to_ref_slice(args);
163         ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
164                                    args.len() as c_uint, True))
165     }
166
167     pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
168         let els: &[TypeRef] = Type::to_ref_slice(els);
169         ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
170                                           els.len() as c_uint,
171                                           packed as Bool))
172     }
173
174     pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
175         let name = CString::new(name).unwrap();
176         ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
177     }
178
179     pub fn empty_struct(ccx: &CrateContext) -> Type {
180         Type::struct_(ccx, &[], false)
181     }
182
183     pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
184         Type::func(&[t], &Type::void(ccx))
185     }
186
187     pub fn array(ty: &Type, len: u64) -> Type {
188         ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
189     }
190
191     pub fn vector(ty: &Type, len: u64) -> Type {
192         ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
193     }
194
195     pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
196         Type::struct_(ccx,
197             &[Type::array(ty, 0), Type::int(ccx)],
198         false)
199     }
200
201     pub fn opaque_vec(ccx: &CrateContext) -> Type {
202         Type::vec(ccx, &Type::i8(ccx))
203     }
204
205     pub fn vtable_ptr(ccx: &CrateContext) -> Type {
206         Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
207     }
208
209     pub fn kind(&self) -> TypeKind {
210         unsafe {
211             llvm::LLVMGetTypeKind(self.to_ref())
212         }
213     }
214
215     pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
216         let slice: &[TypeRef] = Type::to_ref_slice(els);
217         unsafe {
218             llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(),
219                                     els.len() as c_uint, packed as Bool)
220         }
221     }
222
223     pub fn ptr_to(&self) -> Type {
224         ty!(llvm::LLVMPointerType(self.to_ref(), 0))
225     }
226
227     pub fn is_aggregate(&self) -> bool {
228         match self.kind() {
229             TypeKind::Struct | TypeKind::Array => true,
230             _ =>  false
231         }
232     }
233
234     pub fn is_packed(&self) -> bool {
235         unsafe {
236             llvm::LLVMIsPackedStruct(self.to_ref()) == True
237         }
238     }
239
240     pub fn element_type(&self) -> Type {
241         unsafe {
242             Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
243         }
244     }
245
246     /// Return the number of elements in `self` if it is a LLVM vector type.
247     pub fn vector_length(&self) -> usize {
248         unsafe {
249             llvm::LLVMGetVectorSize(self.to_ref()) as usize
250         }
251     }
252
253     pub fn array_length(&self) -> usize {
254         unsafe {
255             llvm::LLVMGetArrayLength(self.to_ref()) as usize
256         }
257     }
258
259     pub fn field_types(&self) -> Vec<Type> {
260         unsafe {
261             let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as usize;
262             if n_elts == 0 {
263                 return Vec::new();
264             }
265             let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts];
266             llvm::LLVMGetStructElementTypes(self.to_ref(),
267                                             elts.as_mut_ptr() as *mut TypeRef);
268             elts
269         }
270     }
271
272     pub fn return_type(&self) -> Type {
273         ty!(llvm::LLVMGetReturnType(self.to_ref()))
274     }
275
276     pub fn func_params(&self) -> Vec<Type> {
277         unsafe {
278             let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
279             let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
280             llvm::LLVMGetParamTypes(self.to_ref(),
281                                     args.as_mut_ptr() as *mut TypeRef);
282             args
283         }
284     }
285
286     pub fn float_width(&self) -> usize {
287         match self.kind() {
288             Float => 32,
289             Double => 64,
290             X86_FP80 => 80,
291             FP128 | PPC_FP128 => 128,
292             _ => panic!("llvm_float_width called on a non-float type")
293         }
294     }
295
296     /// Retrieve the bit width of the integer type `self`.
297     pub fn int_width(&self) -> u64 {
298         unsafe {
299             llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
300         }
301     }
302 }
303
304
305 /* Memory-managed object interface to type handles. */
306
307 pub struct TypeNames {
308     named_types: RefCell<FnvHashMap<String, TypeRef>>,
309 }
310
311 impl TypeNames {
312     pub fn new() -> TypeNames {
313         TypeNames {
314             named_types: RefCell::new(FnvHashMap())
315         }
316     }
317
318     pub fn associate_type(&self, s: &str, t: &Type) {
319         assert!(self.named_types.borrow_mut().insert(s.to_string(),
320                                                      t.to_ref()).is_none());
321     }
322
323     pub fn find_type(&self, s: &str) -> Option<Type> {
324         self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
325     }
326
327     pub fn type_to_string(&self, ty: Type) -> String {
328         ty.to_string()
329     }
330
331     pub fn types_to_str(&self, tys: &[Type]) -> String {
332         let strs: Vec<String> = tys.iter().map(|t| self.type_to_string(*t)).collect();
333         format!("[{}]", strs.join(","))
334     }
335
336     pub fn val_to_string(&self, val: ValueRef) -> String {
337         llvm::build_string(|s| unsafe {
338                 llvm::LLVMWriteValueToString(val, s);
339             }).expect("nun-UTF8 value description from LLVM")
340     }
341 }