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}
;
15 use llvm
::{Float, Double, X86_FP80, PPC_FP128, FP128}
;
17 use context
::CrateContext
;
18 use util
::nodemap
::FnvHashMap
;
21 use rustc
::ty
::layout
;
23 use std
::ffi
::CString
;
27 use std
::cell
::RefCell
;
31 #[derive(Clone, Copy, PartialEq)]
37 impl fmt
::Debug
for Type
{
38 fn fmt(&self, f
: &mut fmt
::Formatter
) -> fmt
::Result
{
39 f
.write_str(&llvm
::build_string(|s
| unsafe {
40 llvm
::LLVMRustWriteTypeToString(self.to_ref(), s
);
41 }).expect("non-UTF8 type description from LLVM"))
46 ($e
:expr
) => ( Type
::from_ref(unsafe { $e }
))
49 /// Wrapper for LLVM TypeRef
52 pub fn from_ref(r
: TypeRef
) -> Type
{
58 #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
59 pub fn to_ref(&self) -> TypeRef
{
63 pub fn to_ref_slice(slice
: &[Type
]) -> &[TypeRef
] {
64 unsafe { mem::transmute(slice) }
67 pub fn void(ccx
: &CrateContext
) -> Type
{
68 ty
!(llvm
::LLVMVoidTypeInContext(ccx
.llcx()))
71 pub fn nil(ccx
: &CrateContext
) -> Type
{
72 Type
::empty_struct(ccx
)
75 pub fn metadata(ccx
: &CrateContext
) -> Type
{
76 ty
!(llvm
::LLVMRustMetadataTypeInContext(ccx
.llcx()))
79 pub fn i1(ccx
: &CrateContext
) -> Type
{
80 ty
!(llvm
::LLVMInt1TypeInContext(ccx
.llcx()))
83 pub fn i8(ccx
: &CrateContext
) -> Type
{
84 ty
!(llvm
::LLVMInt8TypeInContext(ccx
.llcx()))
87 pub fn i16(ccx
: &CrateContext
) -> Type
{
88 ty
!(llvm
::LLVMInt16TypeInContext(ccx
.llcx()))
91 pub fn i32(ccx
: &CrateContext
) -> Type
{
92 ty
!(llvm
::LLVMInt32TypeInContext(ccx
.llcx()))
95 pub fn i64(ccx
: &CrateContext
) -> Type
{
96 ty
!(llvm
::LLVMInt64TypeInContext(ccx
.llcx()))
99 // Creates an integer type with the given number of bits, e.g. i24
100 pub fn ix(ccx
: &CrateContext
, num_bits
: u64) -> Type
{
101 ty
!(llvm
::LLVMIntTypeInContext(ccx
.llcx(), num_bits
as c_uint
))
104 pub fn f32(ccx
: &CrateContext
) -> Type
{
105 ty
!(llvm
::LLVMFloatTypeInContext(ccx
.llcx()))
108 pub fn f64(ccx
: &CrateContext
) -> Type
{
109 ty
!(llvm
::LLVMDoubleTypeInContext(ccx
.llcx()))
112 pub fn bool(ccx
: &CrateContext
) -> Type
{
116 pub fn char(ccx
: &CrateContext
) -> Type
{
120 pub fn i8p(ccx
: &CrateContext
) -> Type
{
121 Type
::i8(ccx
).ptr_to()
124 pub fn int(ccx
: &CrateContext
) -> Type
{
125 match &ccx
.tcx().sess
.target
.target
.target_pointer_width
[..] {
126 "16" => Type
::i16(ccx
),
127 "32" => Type
::i32(ccx
),
128 "64" => Type
::i64(ccx
),
129 tws
=> bug
!("Unsupported target word size for int: {}", tws
),
133 pub fn int_from_ty(ccx
: &CrateContext
, t
: ast
::IntTy
) -> Type
{
135 ast
::IntTy
::Is
=> ccx
.int_type(),
136 ast
::IntTy
::I8
=> Type
::i8(ccx
),
137 ast
::IntTy
::I16
=> Type
::i16(ccx
),
138 ast
::IntTy
::I32
=> Type
::i32(ccx
),
139 ast
::IntTy
::I64
=> Type
::i64(ccx
)
143 pub fn uint_from_ty(ccx
: &CrateContext
, t
: ast
::UintTy
) -> Type
{
145 ast
::UintTy
::Us
=> ccx
.int_type(),
146 ast
::UintTy
::U8
=> Type
::i8(ccx
),
147 ast
::UintTy
::U16
=> Type
::i16(ccx
),
148 ast
::UintTy
::U32
=> Type
::i32(ccx
),
149 ast
::UintTy
::U64
=> Type
::i64(ccx
)
153 pub fn float_from_ty(ccx
: &CrateContext
, t
: ast
::FloatTy
) -> Type
{
155 ast
::FloatTy
::F32
=> Type
::f32(ccx
),
156 ast
::FloatTy
::F64
=> Type
::f64(ccx
),
160 pub fn func(args
: &[Type
], ret
: &Type
) -> Type
{
161 let slice
: &[TypeRef
] = Type
::to_ref_slice(args
);
162 ty
!(llvm
::LLVMFunctionType(ret
.to_ref(), slice
.as_ptr(),
163 args
.len() as c_uint
, False
))
166 pub fn variadic_func(args
: &[Type
], ret
: &Type
) -> Type
{
167 let slice
: &[TypeRef
] = Type
::to_ref_slice(args
);
168 ty
!(llvm
::LLVMFunctionType(ret
.to_ref(), slice
.as_ptr(),
169 args
.len() as c_uint
, True
))
172 pub fn struct_(ccx
: &CrateContext
, els
: &[Type
], packed
: bool
) -> Type
{
173 let els
: &[TypeRef
] = Type
::to_ref_slice(els
);
174 ty
!(llvm
::LLVMStructTypeInContext(ccx
.llcx(), els
.as_ptr(),
179 pub fn named_struct(ccx
: &CrateContext
, name
: &str) -> Type
{
180 let name
= CString
::new(name
).unwrap();
181 ty
!(llvm
::LLVMStructCreateNamed(ccx
.llcx(), name
.as_ptr()))
184 pub fn empty_struct(ccx
: &CrateContext
) -> Type
{
185 Type
::struct_(ccx
, &[], false)
188 pub fn array(ty
: &Type
, len
: u64) -> Type
{
189 ty
!(llvm
::LLVMRustArrayType(ty
.to_ref(), len
))
192 pub fn vector(ty
: &Type
, len
: u64) -> Type
{
193 ty
!(llvm
::LLVMVectorType(ty
.to_ref(), len
as c_uint
))
196 pub fn vec(ccx
: &CrateContext
, ty
: &Type
) -> Type
{
198 &[Type
::array(ty
, 0), Type
::int(ccx
)],
202 pub fn opaque_vec(ccx
: &CrateContext
) -> Type
{
203 Type
::vec(ccx
, &Type
::i8(ccx
))
206 pub fn vtable_ptr(ccx
: &CrateContext
) -> Type
{
207 Type
::func(&[Type
::i8p(ccx
)], &Type
::void(ccx
)).ptr_to().ptr_to()
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 is_aggregate(&self) -> bool
{
230 TypeKind
::Struct
| TypeKind
::Array
=> true,
235 pub fn is_packed(&self) -> bool
{
237 llvm
::LLVMIsPackedStruct(self.to_ref()) == True
241 pub fn element_type(&self) -> Type
{
243 Type
::from_ref(llvm
::LLVMGetElementType(self.to_ref()))
247 /// Return the number of elements in `self` if it is a LLVM vector type.
248 pub fn vector_length(&self) -> usize {
250 llvm
::LLVMGetVectorSize(self.to_ref()) as usize
254 pub fn array_length(&self) -> usize {
256 llvm
::LLVMGetArrayLength(self.to_ref()) as usize
260 pub fn field_types(&self) -> Vec
<Type
> {
262 let n_elts
= llvm
::LLVMCountStructElementTypes(self.to_ref()) as usize;
266 let mut elts
= vec
![Type { rf: ptr::null_mut() }
; n_elts
];
267 llvm
::LLVMGetStructElementTypes(self.to_ref(),
268 elts
.as_mut_ptr() as *mut TypeRef
);
273 pub fn return_type(&self) -> Type
{
274 ty
!(llvm
::LLVMGetReturnType(self.to_ref()))
277 pub fn func_params(&self) -> Vec
<Type
> {
279 let n_args
= llvm
::LLVMCountParamTypes(self.to_ref()) as usize;
280 let mut args
= vec
![Type { rf: ptr::null_mut() }
; n_args
];
281 llvm
::LLVMGetParamTypes(self.to_ref(),
282 args
.as_mut_ptr() as *mut TypeRef
);
287 pub fn float_width(&self) -> usize {
292 FP128
| PPC_FP128
=> 128,
293 _
=> bug
!("llvm_float_width called on a non-float type")
297 /// Retrieve the bit width of the integer type `self`.
298 pub fn int_width(&self) -> u64 {
300 llvm
::LLVMGetIntTypeWidth(self.to_ref()) as u64
304 pub fn from_integer(cx
: &CrateContext
, i
: layout
::Integer
) -> Type
{
305 use rustc
::ty
::layout
::Integer
::*;
309 I16
=> Type
::i16(cx
),
310 I32
=> Type
::i32(cx
),
311 I64
=> Type
::i64(cx
),
315 pub fn from_primitive(ccx
: &CrateContext
, p
: layout
::Primitive
) -> Type
{
317 layout
::Int(i
) => Type
::from_integer(ccx
, i
),
318 layout
::F32
=> Type
::f32(ccx
),
319 layout
::F64
=> Type
::f64(ccx
),
320 layout
::Pointer
=> bug
!("It is not possible to convert Pointer directly to Type.")
325 /* Memory-managed object interface to type handles. */
327 pub struct TypeNames
{
328 named_types
: RefCell
<FnvHashMap
<String
, TypeRef
>>,
332 pub fn new() -> TypeNames
{
334 named_types
: RefCell
::new(FnvHashMap())
338 pub fn associate_type(&self, s
: &str, t
: &Type
) {
339 assert
!(self.named_types
.borrow_mut().insert(s
.to_string(),
340 t
.to_ref()).is_none());
343 pub fn find_type(&self, s
: &str) -> Option
<Type
> {
344 self.named_types
.borrow().get(s
).map(|x
| Type
::from_ref(*x
))