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