]> git.lizzy.rs Git - rust.git/blob - src/librustc/middle/trans/type_.rs
librustc: Automatically change uses of `~[T]` to `Vec<T>` in rustc.
[rust.git] / src / librustc / middle / 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_uppercase_pattern_statics)];
12
13 use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
14 use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
15
16 use middle::trans::context::CrateContext;
17 use middle::trans::base;
18
19 use syntax::ast;
20 use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};
21
22 use std::c_str::ToCStr;
23 use std::vec;
24 use std::cast;
25
26 use std::libc::{c_uint};
27
28 #[deriving(Clone, Eq, Show)]
29 pub struct Type {
30     priv rf: TypeRef
31 }
32
33 macro_rules! ty (
34     ($e:expr) => ( Type::from_ref(unsafe { $e }))
35 )
36
37 /**
38  * Wrapper for LLVM TypeRef
39  */
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() -> Type {
54         ty!(llvm::LLVMVoidTypeInContext(base::task_llcx()))
55     }
56
57     pub fn nil() -> Type {
58         Type::empty_struct()
59     }
60
61     pub fn metadata() -> Type {
62         ty!(llvm::LLVMMetadataTypeInContext(base::task_llcx()))
63     }
64
65     pub fn i1() -> Type {
66         ty!(llvm::LLVMInt1TypeInContext(base::task_llcx()))
67     }
68
69     pub fn i8() -> Type {
70         ty!(llvm::LLVMInt8TypeInContext(base::task_llcx()))
71     }
72
73     pub fn i16() -> Type {
74         ty!(llvm::LLVMInt16TypeInContext(base::task_llcx()))
75     }
76
77     pub fn i32() -> Type {
78         ty!(llvm::LLVMInt32TypeInContext(base::task_llcx()))
79     }
80
81     pub fn i64() -> Type {
82         ty!(llvm::LLVMInt64TypeInContext(base::task_llcx()))
83     }
84
85     pub fn f32() -> Type {
86         ty!(llvm::LLVMFloatTypeInContext(base::task_llcx()))
87     }
88
89     pub fn f64() -> Type {
90         ty!(llvm::LLVMDoubleTypeInContext(base::task_llcx()))
91     }
92
93     pub fn bool() -> Type {
94         Type::i8()
95     }
96
97     pub fn char() -> Type {
98         Type::i32()
99     }
100
101     pub fn i8p() -> Type {
102         Type::i8().ptr_to()
103     }
104
105     pub fn int(arch: Architecture) -> Type {
106         match arch {
107             X86 | Arm | Mips => Type::i32(),
108             X86_64 => Type::i64()
109         }
110     }
111
112     pub fn float(_: Architecture) -> Type {
113         // All architectures currently just use doubles as the default
114         // float size
115         Type::f64()
116     }
117
118     pub fn int_from_ty(ctx: &CrateContext, t: ast::IntTy) -> Type {
119         match t {
120             ast::TyI => ctx.int_type,
121             ast::TyI8 => Type::i8(),
122             ast::TyI16 => Type::i16(),
123             ast::TyI32 => Type::i32(),
124             ast::TyI64 => Type::i64()
125         }
126     }
127
128     pub fn uint_from_ty(ctx: &CrateContext, t: ast::UintTy) -> Type {
129         match t {
130             ast::TyU => ctx.int_type,
131             ast::TyU8 => Type::i8(),
132             ast::TyU16 => Type::i16(),
133             ast::TyU32 => Type::i32(),
134             ast::TyU64 => Type::i64()
135         }
136     }
137
138     pub fn float_from_ty(t: ast::FloatTy) -> Type {
139         match t {
140             ast::TyF32 => Type::f32(),
141             ast::TyF64 => Type::f64()
142         }
143     }
144
145     pub fn size_t(arch: Architecture) -> Type {
146         Type::int(arch)
147     }
148
149     pub fn func(args: &[Type], ret: &Type) -> Type {
150         let vec : &[TypeRef] = unsafe { cast::transmute(args) };
151         ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
152                                    args.len() as c_uint, False))
153     }
154
155     pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
156         let vec : &[TypeRef] = unsafe { cast::transmute(args) };
157         ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
158                                    args.len() as c_uint, True))
159     }
160
161     pub fn ptr(ty: Type) -> Type {
162         ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
163     }
164
165     pub fn struct_(els: &[Type], packed: bool) -> Type {
166         let els : &[TypeRef] = unsafe { cast::transmute(els) };
167         ty!(llvm::LLVMStructTypeInContext(base::task_llcx(), els.as_ptr(),
168                                           els.len() as c_uint, packed as Bool))
169     }
170
171     pub fn named_struct(name: &str) -> Type {
172         let ctx = base::task_llcx();
173         ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
174     }
175
176     pub fn empty_struct() -> Type {
177         Type::struct_([], false)
178     }
179
180     pub fn vtable() -> Type {
181         Type::array(&Type::i8p().ptr_to(), 1)
182     }
183
184     pub fn generic_glue_fn(cx: &CrateContext) -> Type {
185         match cx.tn.find_type("glue_fn") {
186             Some(ty) => return ty,
187             None => ()
188         }
189
190         let ty = Type::glue_fn(Type::i8p());
191         cx.tn.associate_type("glue_fn", &ty);
192
193         return ty;
194     }
195
196     pub fn glue_fn(t: Type) -> Type {
197         Type::func([t], &Type::void())
198     }
199
200     pub fn tydesc(arch: Architecture) -> Type {
201         let mut tydesc = Type::named_struct("tydesc");
202         let glue_fn_ty = Type::glue_fn(Type::i8p()).ptr_to();
203
204         let int_ty = Type::int(arch);
205
206         // Must mirror:
207         //
208         // std::unstable::intrinsics::TyDesc
209
210         let elems = [int_ty,     // size
211                      int_ty,     // align
212                      glue_fn_ty, // drop
213                      glue_fn_ty, // visit
214                      Type::struct_([Type::i8p(), Type::int(arch)], false)]; // name
215         tydesc.set_struct_body(elems, false);
216
217         return tydesc;
218     }
219
220     pub fn array(ty: &Type, len: u64) -> Type {
221         ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
222     }
223
224     pub fn vector(ty: &Type, len: u64) -> Type {
225         ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
226     }
227
228     pub fn vec(arch: Architecture, ty: &Type) -> Type {
229         Type::struct_(
230             [ Type::int(arch), Type::int(arch), Type::array(ty, 0) ],
231         false)
232     }
233
234     pub fn opaque_vec(arch: Architecture) -> Type {
235         Type::vec(arch, &Type::i8())
236     }
237
238     // The box pointed to by @T.
239     pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
240         Type::struct_([
241             ctx.int_type, Type::glue_fn(Type::i8p()).ptr_to(),
242             Type::i8p(), Type::i8p(), ty
243         ], false)
244     }
245
246     pub fn opaque_trait() -> Type {
247         let vtable = Type::glue_fn(Type::i8p()).ptr_to().ptr_to();
248         Type::struct_([vtable, Type::i8p()], false)
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] = cast::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 get_field(&self, idx: uint) -> Type {
270         unsafe {
271             let num_fields = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
272             let mut elems = vec::from_elem(num_fields, 0 as TypeRef);
273
274             llvm::LLVMGetStructElementTypes(self.to_ref(), elems.as_mut_ptr());
275
276             Type::from_ref(elems[idx])
277         }
278     }
279
280     pub fn is_packed(&self) -> bool {
281         unsafe {
282             llvm::LLVMIsPackedStruct(self.to_ref()) == True
283         }
284     }
285
286     pub fn element_type(&self) -> Type {
287         unsafe {
288             Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
289         }
290     }
291
292     pub fn array_length(&self) -> uint {
293         unsafe {
294             llvm::LLVMGetArrayLength(self.to_ref()) as uint
295         }
296     }
297
298     pub fn field_types(&self) -> Vec<Type> {
299         unsafe {
300             let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
301             if n_elts == 0 {
302                 return Vec::new();
303             }
304             let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
305             llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]);
306             cast::transmute(elts)
307         }
308     }
309
310     pub fn return_type(&self) -> Type {
311         ty!(llvm::LLVMGetReturnType(self.to_ref()))
312     }
313
314     pub fn func_params(&self) -> Vec<Type> {
315         unsafe {
316             let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
317             let args = vec::from_elem(n_args, 0 as TypeRef);
318             llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr());
319             cast::transmute(args)
320         }
321     }
322
323     pub fn float_width(&self) -> uint {
324         match self.kind() {
325             Float => 32,
326             Double => 64,
327             X86_FP80 => 80,
328             FP128 | PPC_FP128 => 128,
329             _ => fail!("llvm_float_width called on a non-float type")
330         }
331     }
332 }