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