]> git.lizzy.rs Git - rust.git/blob - src/librustc_codegen_llvm/type_.rs
d4b137926d516a1f0dc39bcc4d7c708d11a4cd15
[rust.git] / src / librustc_codegen_llvm / 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 pub use llvm::Type;
14
15 use llvm;
16 use llvm::{Bool, False, True, TypeKind};
17
18 use context::CodegenCx;
19 use interfaces::TypeMethods;
20
21 use syntax::ast;
22 use rustc::ty::layout::{self, Align, Size};
23 use rustc_data_structures::small_c_str::SmallCStr;
24 use back::write;
25
26 use std::fmt;
27
28 use libc::c_uint;
29
30 impl PartialEq for Type {
31     fn eq(&self, other: &Self) -> bool {
32         self as *const _ == other as *const _
33     }
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, s);
40         }).expect("non-UTF8 type description from LLVM"))
41     }
42 }
43
44 impl TypeMethods for CodegenCx<'ll, 'tcx> {
45
46     fn void(&self) -> &'ll Type {
47         unsafe {
48             llvm::LLVMVoidTypeInContext(self.llcx)
49         }
50     }
51
52     fn metadata(&self) -> &'ll Type {
53         unsafe {
54             llvm::LLVMRustMetadataTypeInContext(self.llcx)
55         }
56     }
57
58     fn i1(&self) -> &'ll Type {
59         unsafe {
60             llvm::LLVMInt1TypeInContext(self.llcx)
61         }
62     }
63
64     fn i8(&self) -> &'ll Type {
65         unsafe {
66             llvm::LLVMInt8TypeInContext(self.llcx)
67         }
68     }
69
70
71     fn i16(&self) -> &'ll Type {
72         unsafe {
73
74             llvm::LLVMInt16TypeInContext(self.llcx)
75         }
76     }
77
78     fn i32(&self) -> &'ll Type {
79         unsafe {
80             llvm::LLVMInt32TypeInContext(self.llcx)
81         }
82     }
83
84     fn i64(&self) -> &'ll Type {
85         unsafe {
86             llvm::LLVMInt64TypeInContext(self.llcx)
87         }
88     }
89
90     fn i128(&self) -> &'ll Type {
91         unsafe {
92             llvm::LLVMIntTypeInContext(self.llcx, 128)
93         }
94     }
95
96     // Creates an integer type with the given number of bits, e.g. i24
97     fn ix(&self, num_bits: u64) -> &'ll Type {
98         unsafe {
99             llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint)
100         }
101     }
102
103     fn f32(&self) -> &'ll Type {
104         unsafe {
105             llvm::LLVMFloatTypeInContext(self.llcx)
106         }
107     }
108
109     fn f64(&self) -> &'ll Type {
110         unsafe {
111             llvm::LLVMDoubleTypeInContext(self.llcx)
112         }
113     }
114
115     fn x86_mmx(&self) -> &'ll Type {
116         unsafe {
117             llvm::LLVMX86MMXTypeInContext(self.llcx)
118         }
119     }
120
121     fn func(
122         &self,
123         args: &[&'ll Type],
124         ret: &'ll Type
125     ) -> &'ll Type {
126         unsafe {
127             llvm::LLVMFunctionType(ret, args.as_ptr(),
128                                    args.len() as c_uint, False)
129         }
130     }
131
132     fn variadic_func(
133         &self,
134         args: &[&'ll Type],
135         ret: &'ll Type
136     ) -> &'ll Type {
137         unsafe {
138             llvm::LLVMFunctionType(ret, args.as_ptr(),
139                                    args.len() as c_uint, True)
140         }
141     }
142
143     fn struct_(
144         &self,
145         els: &[&'ll Type],
146         packed: bool
147     ) -> &'ll Type {
148         unsafe {
149             llvm::LLVMStructTypeInContext(self.llcx, els.as_ptr(),
150                                           els.len() as c_uint,
151                                           packed as Bool)
152         }
153     }
154
155     fn named_struct(&self, name: &str) -> &'ll Type {
156         let name = SmallCStr::new(name);
157         unsafe {
158             llvm::LLVMStructCreateNamed(self.llcx, name.as_ptr())
159         }
160     }
161
162
163     fn array(&self, ty: &'ll Type, len: u64) -> &'ll Type {
164         unsafe {
165             llvm::LLVMRustArrayType(ty, len)
166         }
167     }
168
169     fn vector(&self, ty: &'ll Type, len: u64) -> &'ll Type {
170         unsafe {
171             llvm::LLVMVectorType(ty, len as c_uint)
172         }
173     }
174
175     fn kind(&self, ty: &'ll Type) -> TypeKind {
176         unsafe {
177             llvm::LLVMRustGetTypeKind(ty)
178         }
179     }
180
181     fn set_struct_body(&self, ty: &'ll Type, els: &[&'ll Type], packed: bool) {
182         unsafe {
183             llvm::LLVMStructSetBody(ty, els.as_ptr(),
184                                     els.len() as c_uint, packed as Bool)
185         }
186     }
187
188     fn ptr_to(&self, ty: &'ll Type) -> &'ll Type {
189         assert_ne!(self.kind(ty), TypeKind::Function,
190                    "don't call ptr_to on function types, use ptr_to_llvm_type on FnType instead");
191         unsafe {
192             llvm::LLVMPointerType(ty, 0)
193         }
194     }
195
196     fn element_type(&self, ty: &'ll Type) -> &'ll Type {
197         unsafe {
198             llvm::LLVMGetElementType(ty)
199         }
200     }
201
202     /// Return the number of elements in `self` if it is a LLVM vector type.
203     fn vector_length(&self, ty: &'ll Type) -> usize {
204         unsafe {
205             llvm::LLVMGetVectorSize(ty) as usize
206         }
207     }
208
209     fn func_params(&self, ty: &'ll Type) -> Vec<&'ll Type> {
210         unsafe {
211             let n_args = llvm::LLVMCountParamTypes(ty) as usize;
212             let mut args = Vec::with_capacity(n_args);
213             llvm::LLVMGetParamTypes(ty, args.as_mut_ptr());
214             args.set_len(n_args);
215             args
216         }
217     }
218
219     fn float_width(&self, ty : &'ll Type) -> usize {
220         match self.kind(ty) {
221             TypeKind::Float => 32,
222             TypeKind::Double => 64,
223             TypeKind::X86_FP80 => 80,
224             TypeKind::FP128 | TypeKind::PPc_FP128 => 128,
225             _ => bug!("llvm_float_width called on a non-float type")
226         }
227     }
228
229     /// Retrieve the bit width of the integer type `self`.
230     fn int_width(&self, ty: &'ll Type) -> u64 {
231         unsafe {
232             llvm::LLVMGetIntTypeWidth(ty) as u64
233         }
234     }
235 }
236
237 impl Type {
238     pub fn i8_llcx(llcx: &llvm::Context) -> &Type {
239         unsafe {
240             llvm::LLVMInt8TypeInContext(llcx)
241         }
242     }
243
244     // Creates an integer type with the given number of bits, e.g. i24
245     pub fn ix_llcx(
246         llcx: &llvm::Context,
247         num_bits: u64
248     ) -> &Type {
249         unsafe {
250             llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint)
251         }
252     }
253
254     pub fn i8p_llcx(cx : &write::CodegenContext<'ll>, llcx: &'ll llvm::Context) -> &'ll Type {
255         cx.ptr_to(Type::i8_llcx(llcx))
256     }
257 }
258
259 impl CodegenCx<'ll, 'tcx> {
260     pub fn bool(&self) -> &'ll Type {
261         self.i8()
262     }
263
264     pub fn i8p(&self) -> &'ll Type {
265         self.ptr_to(self.i8())
266     }
267
268     pub fn isize(&self) -> &'ll Type {
269         self.isize_ty
270     }
271
272     pub fn t_int(&self) -> &'ll Type {
273         match &self.sess().target.target.target_c_int_width[..] {
274             "16" => self.i16(),
275             "32" => self.i32(),
276             "64" => self.i64(),
277             width => bug!("Unsupported target_c_int_width: {}", width),
278         }
279     }
280
281     pub fn int_from_ty(
282         &self,
283         t: ast::IntTy
284     ) -> &'ll Type {
285         match t {
286             ast::IntTy::Isize => self.isize_ty,
287             ast::IntTy::I8 => self.i8(),
288             ast::IntTy::I16 => self.i16(),
289             ast::IntTy::I32 => self.i32(),
290             ast::IntTy::I64 => self.i64(),
291             ast::IntTy::I128 => self.i128(),
292         }
293     }
294
295     pub fn uint_from_ty(
296         &self,
297         t: ast::UintTy
298     ) -> &'ll Type {
299         match t {
300             ast::UintTy::Usize => self.isize_ty,
301             ast::UintTy::U8 => self.i8(),
302             ast::UintTy::U16 => self.i16(),
303             ast::UintTy::U32 => self.i32(),
304             ast::UintTy::U64 => self.i64(),
305             ast::UintTy::U128 => self.i128(),
306         }
307     }
308
309     pub fn float_from_ty(
310         &self,
311         t: ast::FloatTy
312     ) -> &'ll Type {
313         match t {
314             ast::FloatTy::F32 => self.f32(),
315             ast::FloatTy::F64 => self.f64(),
316         }
317     }
318
319     pub fn from_integer(&self, i: layout::Integer) -> &'ll Type {
320         use rustc::ty::layout::Integer::*;
321         match i {
322             I8 => self.i8(),
323             I16 => self.i16(),
324             I32 => self.i32(),
325             I64 => self.i64(),
326             I128 => self.i128(),
327         }
328     }
329
330     /// Return a LLVM type that has at most the required alignment,
331     /// as a conservative approximation for unknown pointee types.
332     pub fn pointee_for_abi_align(&self, align: Align) -> &'ll Type {
333         // FIXME(eddyb) We could find a better approximation if ity.align < align.
334         let ity = layout::Integer::approximate_abi_align(self, align);
335         self.from_integer(ity)
336     }
337
338     /// Return a LLVM type that has at most the required alignment,
339     /// and exactly the required size, as a best-effort padding array.
340     pub fn padding_filler(&self, size: Size, align: Align) -> &'ll Type {
341         let unit = layout::Integer::approximate_abi_align(self, align);
342         let size = size.bytes();
343         let unit_size = unit.size().bytes();
344         assert_eq!(size % unit_size, 0);
345         self.array(self.from_integer(unit), size / unit_size)
346     }
347 }