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