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::{TypeRef, Bool, False, True, TypeKind, ValueRef};
15 use llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
17 use trans::context::CrateContext;
18 use util::nodemap::FnvHashMap;
22 use std::ffi::CString;
25 use std::cell::RefCell;
29 #[derive(Clone, Copy, PartialEq, Debug)]
36 ($e:expr) => ( Type::from_ref(unsafe { $e }))
39 /// Wrapper for LLVM TypeRef
42 pub fn from_ref(r: TypeRef) -> Type {
48 #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
49 pub fn to_ref(&self) -> TypeRef {
53 pub fn to_string(self: Type) -> String {
54 llvm::build_string(|s| unsafe {
55 llvm::LLVMWriteTypeToString(self.to_ref(), s);
56 }).expect("non-UTF8 type description from LLVM")
59 pub fn to_ref_slice(slice: &[Type]) -> &[TypeRef] {
60 unsafe { mem::transmute(slice) }
63 pub fn void(ccx: &CrateContext) -> Type {
64 ty!(llvm::LLVMVoidTypeInContext(ccx.llcx()))
67 pub fn nil(ccx: &CrateContext) -> Type {
68 Type::empty_struct(ccx)
71 pub fn metadata(ccx: &CrateContext) -> Type {
72 ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx()))
75 pub fn i1(ccx: &CrateContext) -> Type {
76 ty!(llvm::LLVMInt1TypeInContext(ccx.llcx()))
79 pub fn i8(ccx: &CrateContext) -> Type {
80 ty!(llvm::LLVMInt8TypeInContext(ccx.llcx()))
83 pub fn i16(ccx: &CrateContext) -> Type {
84 ty!(llvm::LLVMInt16TypeInContext(ccx.llcx()))
87 pub fn i32(ccx: &CrateContext) -> Type {
88 ty!(llvm::LLVMInt32TypeInContext(ccx.llcx()))
91 pub fn i64(ccx: &CrateContext) -> Type {
92 ty!(llvm::LLVMInt64TypeInContext(ccx.llcx()))
95 // Creates an integer type with the given number of bits, e.g. i24
96 pub fn ix(ccx: &CrateContext, num_bits: u64) -> Type {
97 ty!(llvm::LLVMIntTypeInContext(ccx.llcx(), num_bits as c_uint))
100 pub fn f32(ccx: &CrateContext) -> Type {
101 ty!(llvm::LLVMFloatTypeInContext(ccx.llcx()))
104 pub fn f64(ccx: &CrateContext) -> Type {
105 ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx()))
108 pub fn bool(ccx: &CrateContext) -> Type {
112 pub fn char(ccx: &CrateContext) -> Type {
116 pub fn i8p(ccx: &CrateContext) -> Type {
117 Type::i8(ccx).ptr_to()
120 pub fn int(ccx: &CrateContext) -> Type {
121 match &ccx.tcx().sess.target.target.target_pointer_width[..] {
122 "32" => Type::i32(ccx),
123 "64" => Type::i64(ccx),
124 tws => panic!("Unsupported target word size for int: {}", tws),
128 pub fn int_from_ty(ccx: &CrateContext, t: hir::IntTy) -> Type {
130 hir::TyIs => ccx.int_type(),
131 hir::TyI8 => Type::i8(ccx),
132 hir::TyI16 => Type::i16(ccx),
133 hir::TyI32 => Type::i32(ccx),
134 hir::TyI64 => Type::i64(ccx)
138 pub fn uint_from_ty(ccx: &CrateContext, t: hir::UintTy) -> Type {
140 hir::TyUs => ccx.int_type(),
141 hir::TyU8 => Type::i8(ccx),
142 hir::TyU16 => Type::i16(ccx),
143 hir::TyU32 => Type::i32(ccx),
144 hir::TyU64 => Type::i64(ccx)
148 pub fn float_from_ty(ccx: &CrateContext, t: hir::FloatTy) -> Type {
150 hir::TyF32 => Type::f32(ccx),
151 hir::TyF64 => Type::f64(ccx),
155 pub fn func(args: &[Type], ret: &Type) -> Type {
156 let slice: &[TypeRef] = Type::to_ref_slice(args);
157 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
158 args.len() as c_uint, False))
161 pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
162 let slice: &[TypeRef] = Type::to_ref_slice(args);
163 ty!(llvm::LLVMFunctionType(ret.to_ref(), slice.as_ptr(),
164 args.len() as c_uint, True))
167 pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
168 let els: &[TypeRef] = Type::to_ref_slice(els);
169 ty!(llvm::LLVMStructTypeInContext(ccx.llcx(), els.as_ptr(),
174 pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
175 let name = CString::new(name).unwrap();
176 ty!(llvm::LLVMStructCreateNamed(ccx.llcx(), name.as_ptr()))
179 pub fn empty_struct(ccx: &CrateContext) -> Type {
180 Type::struct_(ccx, &[], false)
183 pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
184 Type::func(&[t], &Type::void(ccx))
187 pub fn array(ty: &Type, len: u64) -> Type {
188 ty!(llvm::LLVMRustArrayType(ty.to_ref(), len))
191 pub fn vector(ty: &Type, len: u64) -> Type {
192 ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
195 pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
197 &[Type::array(ty, 0), Type::int(ccx)],
201 pub fn opaque_vec(ccx: &CrateContext) -> Type {
202 Type::vec(ccx, &Type::i8(ccx))
205 pub fn vtable_ptr(ccx: &CrateContext) -> Type {
206 Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to()
209 pub fn kind(&self) -> TypeKind {
211 llvm::LLVMGetTypeKind(self.to_ref())
215 pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
216 let slice: &[TypeRef] = Type::to_ref_slice(els);
218 llvm::LLVMStructSetBody(self.to_ref(), slice.as_ptr(),
219 els.len() as c_uint, packed as Bool)
223 pub fn ptr_to(&self) -> Type {
224 ty!(llvm::LLVMPointerType(self.to_ref(), 0))
227 pub fn is_aggregate(&self) -> bool {
229 TypeKind::Struct | TypeKind::Array => true,
234 pub fn is_packed(&self) -> bool {
236 llvm::LLVMIsPackedStruct(self.to_ref()) == True
240 pub fn element_type(&self) -> Type {
242 Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
246 /// Return the number of elements in `self` if it is a LLVM vector type.
247 pub fn vector_length(&self) -> usize {
249 llvm::LLVMGetVectorSize(self.to_ref()) as usize
253 pub fn array_length(&self) -> usize {
255 llvm::LLVMGetArrayLength(self.to_ref()) as usize
259 pub fn field_types(&self) -> Vec<Type> {
261 let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as usize;
265 let mut elts = vec![Type { rf: ptr::null_mut() }; n_elts];
266 llvm::LLVMGetStructElementTypes(self.to_ref(),
267 elts.as_mut_ptr() as *mut TypeRef);
272 pub fn return_type(&self) -> Type {
273 ty!(llvm::LLVMGetReturnType(self.to_ref()))
276 pub fn func_params(&self) -> Vec<Type> {
278 let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as usize;
279 let mut args = vec![Type { rf: ptr::null_mut() }; n_args];
280 llvm::LLVMGetParamTypes(self.to_ref(),
281 args.as_mut_ptr() as *mut TypeRef);
286 pub fn float_width(&self) -> usize {
291 FP128 | PPC_FP128 => 128,
292 _ => panic!("llvm_float_width called on a non-float type")
296 /// Retrieve the bit width of the integer type `self`.
297 pub fn int_width(&self) -> u64 {
299 llvm::LLVMGetIntTypeWidth(self.to_ref()) as u64
305 /* Memory-managed object interface to type handles. */
307 pub struct TypeNames {
308 named_types: RefCell<FnvHashMap<String, TypeRef>>,
312 pub fn new() -> TypeNames {
314 named_types: RefCell::new(FnvHashMap())
318 pub fn associate_type(&self, s: &str, t: &Type) {
319 assert!(self.named_types.borrow_mut().insert(s.to_string(),
320 t.to_ref()).is_none());
323 pub fn find_type(&self, s: &str) -> Option<Type> {
324 self.named_types.borrow().get(s).map(|x| Type::from_ref(*x))
327 pub fn type_to_string(&self, ty: Type) -> String {
331 pub fn types_to_str(&self, tys: &[Type]) -> String {
332 let strs: Vec<String> = tys.iter().map(|t| self.type_to_string(*t)).collect();
333 format!("[{}]", strs.join(","))
336 pub fn val_to_string(&self, val: ValueRef) -> String {
337 llvm::build_string(|s| unsafe {
338 llvm::LLVMWriteValueToString(val, s);
339 }).expect("nun-UTF8 value description from LLVM")