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.
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.
11 #![allow(non_upper_case_globals)]
14 use llvm::{ContextRef, TypeRef, Bool, False, True, TypeKind};
15 use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
17 use context::CrateContext;
20 use rustc::ty::layout::{self, Align};
22 use std::ffi::CString;
29 #[derive(Clone, Copy, PartialEq)]
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"))
44 ($e:expr) => ( Type::from_ref(unsafe { $e }))
47 /// Wrapper for LLVM TypeRef
50 pub fn from_ref(r: TypeRef) -> Type {
56 #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
57 pub fn to_ref(&self) -> TypeRef {
61 pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
62 unsafe { mem::transmute(slice) }
65 pub fn void(ccx: &CrateContext) -> Type {
66 ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
69 pub fn metadata(ccx: &CrateContext) -> Type {
70 ty!(llvm::LLVMRustMetadataTypeInContext(ccx.llcx()))
73 pub fn i1(ccx: &CrateContext) -> Type {
74 ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
77 pub fn i8(ccx: &CrateContext) -> Type {
78 ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
81 pub fn i8_llcx(llcx: ContextRef) -> Type {
82 ty!(llvm::LLVMInt8TypeInContext(llcx))
85 pub fn i16(ccx: &CrateContext) -> Type {
86 ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
89 pub fn i32(ccx: &CrateContext) -> Type {
90 ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
93 pub fn i64(ccx: &CrateContext) -> Type {
94 ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
97 pub fn i128(ccx: &CrateContext) -> Type {
98 ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), 128))
101 // Creates an integer type with the given number of bits, e.g. i24
102 pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
103 ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
106 pub fn f32(ccx: &CrateContext) -> Type {
107 ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
110 pub fn f64(ccx: &CrateContext) -> Type {
111 ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
114 pub fn bool(ccx: &CrateContext) -> Type {
118 pub fn char(ccx: &CrateContext) -> Type {
122 pub fn i8p(ccx: &CrateContext) -> Type {
123 Type::i8(ccx).ptr_to()
126 pub fn i8p_llcx(llcx: ContextRef) -> Type {
127 Type::i8_llcx(llcx).ptr_to()
130 pub fn isize(ccx: &CrateContext) -> Type {
131 match &ccx.tcx().sess.target.target.target_pointer_width[..] {
132 "16" => Type::i16(ccx),
133 "32" => Type::i32(ccx),
134 "64" => Type::i64(ccx),
135 tws => bug!("Unsupported target word size for int: {}", tws),
139 pub fn c_int(ccx: &CrateContext) -> Type {
140 match &ccx.tcx().sess.target.target.target_c_int_width[..] {
141 "16" => Type::i16(ccx),
142 "32" => Type::i32(ccx),
143 "64" => Type::i64(ccx),
144 width => bug!("Unsupported target_c_int_width: {}", width),
148 pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
150 ast::IntTy::Is => ccx.isize_ty(),
151 ast::IntTy::I8 => Type::i8(ccx),
152 ast::IntTy::I16 => Type::i16(ccx),
153 ast::IntTy::I32 => Type::i32(ccx),
154 ast::IntTy::I64 => Type::i64(ccx),
155 ast::IntTy::I128 => Type::i128(ccx),
159 pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
161 ast::UintTy::Us => ccx.isize_ty(),
162 ast::UintTy::U8 => Type::i8(ccx),
163 ast::UintTy::U16 => Type::i16(ccx),
164 ast::UintTy::U32 => Type::i32(ccx),
165 ast::UintTy::U64 => Type::i64(ccx),
166 ast::UintTy::U128 => Type::i128(ccx),
170 pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
172 ast::FloatTy::F32 => Type::f32(ccx),
173 ast::FloatTy::F64 => Type::f64(ccx),
177 pub fn func(args: &[Type], ret: &Type) -> Type {
178 let slice: &[TypeRef] = Type::to_ref_slice(args);
179 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
180 args.len() as c_uint, False))
183 pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
184 let slice: &[TypeRef] = Type::to_ref_slice(args);
185 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
186 args.len() as c_uint, True))
189 pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
190 let els: &[TypeRef] = Type::to_ref_slice(els);
191 ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
196 pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
197 let name = CString::new(name).unwrap();
198 ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
202 pub fn array(ty: &Type, len: u64) -> Type {
203 ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
206 pub fn vector(ty: &Type, len: u64) -> Type {
207 ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
210 pub fn kind(&self) -> TypeKind {
212 llvm::LLVMRustGetTypeKind(self.to_ref())
216 pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
217 let slice: &[TypeRef] = Type::to_ref_slice(els);
219 llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(),
220 els.len() as c_uint, packed as Bool)
224 pub fn ptr_to(&self) -> Type {
225 ty!(llvm::LLVMPointerType(self.to_ref(), 0))
228 pub fn element_type(&self) -> Type {
230 Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
234 /// Return the number of elements in `self` if it is a LLVM vector type.
235 pub fn vector_length(&self) -> usize {
237 llvm::LLVMGetVectorSize(self.to_ref()) as usize
241 pub fn func_params(&self) -> Vec<Type> {
243 let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
244 let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
245 llvm::LLVMGetParamTypes(self.to_ref(),
246 args.as_mut_ptr() as *mut TypeRef);
251 pub fn float_width(&self) -> usize {
256 FP128 | PPC_FP128 => 128,
257 _ => bug!("llvm_float_width called on a non-float type")
261 /// Retrieve the bit width of the integer type `self`.
262 pub fn int_width(&self) -> u64 {
264 llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
268 pub fn from_integer(cx: &CrateContext, i: layout::Integer) -> Type {
269 use rustc::ty::layout::Integer::*;
272 I16 => Type::i16(cx),
273 I32 => Type::i32(cx),
274 I64 => Type::i64(cx),
275 I128 => Type::i128(cx),
279 /// Return a LLVM type that has at most the required alignment,
280 /// as a conservative approximation for unknown pointee types.
281 pub fn pointee_for_abi_align(ccx: &CrateContext, align: Align) -> Type {
282 if let Some(ity) = layout::Integer::for_abi_align(ccx, align) {
283 Type::from_integer(ccx, ity)
285 // FIXME(eddyb) We could find a better approximation here.
290 pub fn x86_mmx(ccx: &CrateContext) -> Type {
291 ty!(llvm::LLVMX86MMXTypeInContext(ccx.llcx()))