]> git.proxmox.com Git - rustc.git/blob - src/librustc_trans/type_.rs
New upstream version 1.12.0+dfsg1
[rustc.git] / src / librustc_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};
15 use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
16
17 use context::CrateContext;
18 use util::nodemap::FnvHashMap;
19
20 use syntax::ast;
21
22 use std::ffi::CString;
23 use std::fmt;
24 use std::mem;
25 use std::ptr;
26 use std::cell::RefCell;
27
28 use libc::c_uint;
29
30 #[derive(Clone, Copy, PartialEq)]
31 #[repr(C)]
32 pub struct Type {
33 rf: TypeRef
34 }
35
36 impl fmt::Debug for Type {
37 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
38 f.write_str(&llvm::build_string(|s| unsafe {
39 llvm::LLVMRustWriteTypeToString(self.to_ref(), s);
40 }).expect("non-UTF8 type description from LLVM"))
41 }
42 }
43
44 macro_rules! ty {
45 ($e:expr) => ( Type::from_ref(unsafe { $e }))
46 }
47
48 /// Wrapper for LLVM TypeRef
49 impl Type {
50 #[inline(always)]
51 pub fn from_ref(r: TypeRef) -> Type {
52 Type {
53 rf: r
54 }
55 }
56
57 #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
58 pub fn to_ref(&self) -> TypeRef {
59 self.rf
60 }
61
62 pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
63 unsafe { mem::transmute(slice) }
64 }
65
66 pub fn void(ccx: &CrateContext) -> Type {
67 ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
68 }
69
70 pub fn nil(ccx: &CrateContext) -> Type {
71 Type::empty_struct(ccx)
72 }
73
74 pub fn metadata(ccx: &CrateContext) -> Type {
75 ty!(llvm::LLVMRustMetadataTypeInContext(ccx.llcx()))
76 }
77
78 pub fn i1(ccx: &CrateContext) -> Type {
79 ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
80 }
81
82 pub fn i8(ccx: &CrateContext) -> Type {
83 ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
84 }
85
86 pub fn i16(ccx: &CrateContext) -> Type {
87 ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
88 }
89
90 pub fn i32(ccx: &CrateContext) -> Type {
91 ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
92 }
93
94 pub fn i64(ccx: &CrateContext) -> Type {
95 ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
96 }
97
98 // Creates an integer type with the given number of bits, e.g. i24
99 pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
100 ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
101 }
102
103 pub fn f32(ccx: &CrateContext) -> Type {
104 ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
105 }
106
107 pub fn f64(ccx: &CrateContext) -> Type {
108 ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
109 }
110
111 pub fn bool(ccx: &CrateContext) -> Type {
112 Type::i8(ccx)
113 }
114
115 pub fn char(ccx: &CrateContext) -> Type {
116 Type::i32(ccx)
117 }
118
119 pub fn i8p(ccx: &CrateContext) -> Type {
120 Type::i8(ccx).ptr_to()
121 }
122
123 pub fn int(ccx: &CrateContext) -> Type {
124 match &ccx.tcx().sess.target.target.target_pointer_width[..] {
125 "16" => Type::i16(ccx),
126 "32" => Type::i32(ccx),
127 "64" => Type::i64(ccx),
128 tws => bug!("Unsupported target word size for int: {}", tws),
129 }
130 }
131
132 pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
133 match t {
134 ast::IntTy::Is => ccx.int_type(),
135 ast::IntTy::I8 => Type::i8(ccx),
136 ast::IntTy::I16 => Type::i16(ccx),
137 ast::IntTy::I32 => Type::i32(ccx),
138 ast::IntTy::I64 => Type::i64(ccx)
139 }
140 }
141
142 pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
143 match t {
144 ast::UintTy::Us => ccx.int_type(),
145 ast::UintTy::U8 => Type::i8(ccx),
146 ast::UintTy::U16 => Type::i16(ccx),
147 ast::UintTy::U32 => Type::i32(ccx),
148 ast::UintTy::U64 => Type::i64(ccx)
149 }
150 }
151
152 pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
153 match t {
154 ast::FloatTy::F32 => Type::f32(ccx),
155 ast::FloatTy::F64 => Type::f64(ccx),
156 }
157 }
158
159 pub fn func(args: &[Type], ret: &Type) -> Type {
160 let slice: &[TypeRef] = Type::to_ref_slice(args);
161 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
162 args.len() as c_uint, False))
163 }
164
165 pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
166 let slice: &[TypeRef] = Type::to_ref_slice(args);
167 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
168 args.len() as c_uint, True))
169 }
170
171 pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
172 let els: &[TypeRef] = Type::to_ref_slice(els);
173 ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
174 els.len() as c_uint,
175 packed as Bool))
176 }
177
178 pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
179 let name = CString::new(name).unwrap();
180 ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
181 }
182
183 pub fn empty_struct(ccx: &CrateContext) -> Type {
184 Type::struct_(ccx, &[], false)
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::func(&[Type::i8p(ccx)], &Type::void(ccx)).ptr_to().ptr_to()
207 }
208
209 pub fn kind(&self) -> TypeKind {
210 unsafe {
211 llvm::LLVMRustGetTypeKind(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 _ => bug!("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 /* Memory-managed object interface to type handles. */
305
306 pub struct TypeNames {
307 named_types: RefCell<FnvHashMap<String, TypeRef>>,
308 }
309
310 impl TypeNames {
311 pub fn new() -> TypeNames {
312 TypeNames {
313 named_types: RefCell::new(FnvHashMap())
314 }
315 }
316
317 pub fn associate_type(&self, s: &str, t: &Type) {
318 assert!(self.named_types.borrow_mut().insert(s.to_string(),
319 t.to_ref()).is_none());
320 }
321
322 pub fn find_type(&self, s: &str) -> Option<Type> {
323 self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
324 }
325 }