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