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