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_uppercase_pattern_statics)];
13 use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
14 use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
16 use middle::trans::context::CrateContext;
17 use middle::trans::base;
20 use syntax::abi::{Architecture, X86, X86_64, Arm, Mips};
22 use std::c_str::ToCStr;
26 use std::libc::{c_uint};
28 #[deriving(Clone, Eq, Show)]
34 ($e:expr) => ( Type::from_ref(unsafe { $e }))
38 * 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 void() -> Type {
54 ty!(llvm::LLVMVoidTypeInContext(base::task_llcx()))
57 pub fn nil() -> Type {
61 pub fn metadata() -> Type {
62 ty!(llvm::LLVMMetadataTypeInContext(base::task_llcx()))
66 ty!(llvm::LLVMInt1TypeInContext(base::task_llcx()))
70 ty!(llvm::LLVMInt8TypeInContext(base::task_llcx()))
73 pub fn i16() -> Type {
74 ty!(llvm::LLVMInt16TypeInContext(base::task_llcx()))
77 pub fn i32() -> Type {
78 ty!(llvm::LLVMInt32TypeInContext(base::task_llcx()))
81 pub fn i64() -> Type {
82 ty!(llvm::LLVMInt64TypeInContext(base::task_llcx()))
85 pub fn f32() -> Type {
86 ty!(llvm::LLVMFloatTypeInContext(base::task_llcx()))
89 pub fn f64() -> Type {
90 ty!(llvm::LLVMDoubleTypeInContext(base::task_llcx()))
93 pub fn bool() -> Type {
97 pub fn char() -> Type {
101 pub fn i8p() -> Type {
105 pub fn int(arch: Architecture) -> Type {
107 X86 | Arm | Mips => Type::i32(),
108 X86_64 => Type::i64()
112 pub fn float(_: Architecture) -> Type {
113 // All architectures currently just use doubles as the default
118 pub fn int_from_ty(ctx: &CrateContext, t: ast::IntTy) -> Type {
120 ast::TyI => ctx.int_type,
121 ast::TyI8 => Type::i8(),
122 ast::TyI16 => Type::i16(),
123 ast::TyI32 => Type::i32(),
124 ast::TyI64 => Type::i64()
128 pub fn uint_from_ty(ctx: &CrateContext, t: ast::UintTy) -> Type {
130 ast::TyU => ctx.int_type,
131 ast::TyU8 => Type::i8(),
132 ast::TyU16 => Type::i16(),
133 ast::TyU32 => Type::i32(),
134 ast::TyU64 => Type::i64()
138 pub fn float_from_ty(t: ast::FloatTy) -> Type {
140 ast::TyF32 => Type::f32(),
141 ast::TyF64 => Type::f64()
145 pub fn size_t(arch: Architecture) -> Type {
149 pub fn func(args: &[Type], ret: &Type) -> Type {
150 let vec : &[TypeRef] = unsafe { cast::transmute(args) };
151 ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
152 args.len() as c_uint, False))
155 pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
156 let vec : &[TypeRef] = unsafe { cast::transmute(args) };
157 ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
158 args.len() as c_uint, True))
161 pub fn ptr(ty: Type) -> Type {
162 ty!(llvm::LLVMPointerType(ty.to_ref(), 0 as c_uint))
165 pub fn struct_(els: &[Type], packed: bool) -> Type {
166 let els : &[TypeRef] = unsafe { cast::transmute(els) };
167 ty!(llvm::LLVMStructTypeInContext(base::task_llcx(), els.as_ptr(),
168 els.len() as c_uint, packed as Bool))
171 pub fn named_struct(name: &str) -> Type {
172 let ctx = base::task_llcx();
173 ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ctx, s)))
176 pub fn empty_struct() -> Type {
177 Type::struct_([], false)
180 pub fn vtable() -> Type {
181 Type::array(&Type::i8p().ptr_to(), 1)
184 pub fn generic_glue_fn(cx: &CrateContext) -> Type {
185 match cx.tn.find_type("glue_fn") {
186 Some(ty) => return ty,
190 let ty = Type::glue_fn(Type::i8p());
191 cx.tn.associate_type("glue_fn", &ty);
196 pub fn glue_fn(t: Type) -> Type {
197 Type::func([t], &Type::void())
200 pub fn tydesc(arch: Architecture) -> Type {
201 let mut tydesc = Type::named_struct("tydesc");
202 let glue_fn_ty = Type::glue_fn(Type::i8p()).ptr_to();
204 let int_ty = Type::int(arch);
208 // std::unstable::intrinsics::TyDesc
210 let elems = [int_ty, // size
214 Type::struct_([Type::i8p(), Type::int(arch)], false)]; // name
215 tydesc.set_struct_body(elems, false);
220 pub fn array(ty: &Type, len: u64) -> Type {
221 ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
224 pub fn vector(ty: &Type, len: u64) -> Type {
225 ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
228 pub fn vec(arch: Architecture, ty: &Type) -> Type {
230 [ Type::int(arch), Type::int(arch), Type::array(ty, 0) ],
234 pub fn opaque_vec(arch: Architecture) -> Type {
235 Type::vec(arch, &Type::i8())
238 // The box pointed to by @T.
239 pub fn at_box(ctx: &CrateContext, ty: Type) -> Type {
241 ctx.int_type, Type::glue_fn(Type::i8p()).ptr_to(),
242 Type::i8p(), Type::i8p(), ty
246 pub fn opaque_trait() -> Type {
247 let vtable = Type::glue_fn(Type::i8p()).ptr_to().ptr_to();
248 Type::struct_([vtable, Type::i8p()], false)
251 pub fn kind(&self) -> TypeKind {
253 llvm::LLVMGetTypeKind(self.to_ref())
257 pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
259 let vec : &[TypeRef] = cast::transmute(els);
260 llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
261 els.len() as c_uint, packed as Bool)
265 pub fn ptr_to(&self) -> Type {
266 ty!(llvm::LLVMPointerType(self.to_ref(), 0))
269 pub fn get_field(&self, idx: uint) -> Type {
271 let num_fields = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
272 let mut elems = vec::from_elem(num_fields, 0 as TypeRef);
274 llvm::LLVMGetStructElementTypes(self.to_ref(), elems.as_mut_ptr());
276 Type::from_ref(elems[idx])
280 pub fn is_packed(&self) -> bool {
282 llvm::LLVMIsPackedStruct(self.to_ref()) == True
286 pub fn element_type(&self) -> Type {
288 Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
292 pub fn array_length(&self) -> uint {
294 llvm::LLVMGetArrayLength(self.to_ref()) as uint
298 pub fn field_types(&self) -> Vec<Type> {
300 let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
304 let mut elts = vec::from_elem(n_elts, 0 as TypeRef);
305 llvm::LLVMGetStructElementTypes(self.to_ref(), &mut elts[0]);
306 cast::transmute(elts)
310 pub fn return_type(&self) -> Type {
311 ty!(llvm::LLVMGetReturnType(self.to_ref()))
314 pub fn func_params(&self) -> Vec<Type> {
316 let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
317 let args = vec::from_elem(n_args, 0 as TypeRef);
318 llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr());
319 cast::transmute(args)
323 pub fn float_width(&self) -> uint {
328 FP128 | PPC_FP128 => 128,
329 _ => fail!("llvm_float_width called on a non-float type")