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_uppercase_pattern_statics)]
12
13 use lib::llvm::{llvm, TypeRef, Bool, False, True, TypeKind};
14 use lib::llvm::{Float, Double, X86_FP80, PPC_FP128, FP128};
15
16 use middle::trans::context::CrateContext;
17
18 use syntax::ast;
19 use syntax::abi::{X86, X86_64, Arm, Mips};
20
21 use std::c_str::ToCStr;
22 use std::cast;
23
24 use libc::{c_uint};
25
26 #[deriving(Clone, Eq, Show)]
27 pub struct Type {
28 rf: TypeRef
29 }
30
31 macro_rules! ty (
32 ($e:expr) => ( Type::from_ref(unsafe { $e }))
33 )
34
35 /**
36 * Wrapper for LLVM TypeRef
37 */
38 impl Type {
39 #[inline(always)]
40 pub fn from_ref(r: TypeRef) -> Type {
41 Type {
42 rf: r
43 }
44 }
45
46 #[inline(always)] // So it doesn't kill --opt-level=0 builds of the compiler
47 pub fn to_ref(&self) -> TypeRef {
48 self.rf
49 }
50
51 pub fn void(ccx: &CrateContext) -> Type {
52 ty!(llvm::LLVMVoidTypeInContext(ccx.llcx))
53 }
54
55 pub fn nil(ccx: &CrateContext) -> Type {
56 Type::empty_struct(ccx)
57 }
58
59 pub fn metadata(ccx: &CrateContext) -> Type {
60 ty!(llvm::LLVMMetadataTypeInContext(ccx.llcx))
61 }
62
63 pub fn i1(ccx: &CrateContext) -> Type {
64 ty!(llvm::LLVMInt1TypeInContext(ccx.llcx))
65 }
66
67 pub fn i8(ccx: &CrateContext) -> Type {
68 ty!(llvm::LLVMInt8TypeInContext(ccx.llcx))
69 }
70
71 pub fn i16(ccx: &CrateContext) -> Type {
72 ty!(llvm::LLVMInt16TypeInContext(ccx.llcx))
73 }
74
75 pub fn i32(ccx: &CrateContext) -> Type {
76 ty!(llvm::LLVMInt32TypeInContext(ccx.llcx))
77 }
78
79 pub fn i64(ccx: &CrateContext) -> Type {
80 ty!(llvm::LLVMInt64TypeInContext(ccx.llcx))
81 }
82
83 pub fn f32(ccx: &CrateContext) -> Type {
84 ty!(llvm::LLVMFloatTypeInContext(ccx.llcx))
85 }
86
87 pub fn f64(ccx: &CrateContext) -> Type {
88 ty!(llvm::LLVMDoubleTypeInContext(ccx.llcx))
89 }
90
91 pub fn f128(ccx: &CrateContext) -> Type {
92 ty!(llvm::LLVMFP128TypeInContext(ccx.llcx))
93 }
94
95 pub fn bool(ccx: &CrateContext) -> Type {
96 Type::i8(ccx)
97 }
98
99 pub fn char(ccx: &CrateContext) -> Type {
100 Type::i32(ccx)
101 }
102
103 pub fn i8p(ccx: &CrateContext) -> Type {
104 Type::i8(ccx).ptr_to()
105 }
106
107 pub fn int(ccx: &CrateContext) -> Type {
108 match ccx.tcx.sess.targ_cfg.arch {
109 X86 | Arm | Mips => Type::i32(ccx),
110 X86_64 => Type::i64(ccx)
111 }
112 }
113
114 pub fn int_from_ty(ccx: &CrateContext, t: ast::IntTy) -> Type {
115 match t {
116 ast::TyI => ccx.int_type,
117 ast::TyI8 => Type::i8(ccx),
118 ast::TyI16 => Type::i16(ccx),
119 ast::TyI32 => Type::i32(ccx),
120 ast::TyI64 => Type::i64(ccx)
121 }
122 }
123
124 pub fn uint_from_ty(ccx: &CrateContext, t: ast::UintTy) -> Type {
125 match t {
126 ast::TyU => ccx.int_type,
127 ast::TyU8 => Type::i8(ccx),
128 ast::TyU16 => Type::i16(ccx),
129 ast::TyU32 => Type::i32(ccx),
130 ast::TyU64 => Type::i64(ccx)
131 }
132 }
133
134 pub fn float_from_ty(ccx: &CrateContext, t: ast::FloatTy) -> Type {
135 match t {
136 ast::TyF32 => Type::f32(ccx),
137 ast::TyF64 => Type::f64(ccx),
138 ast::TyF128 => Type::f128(ccx)
139 }
140 }
141
142 pub fn func(args: &[Type], ret: &Type) -> Type {
143 let vec : &[TypeRef] = unsafe { cast::transmute(args) };
144 ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
145 args.len() as c_uint, False))
146 }
147
148 pub fn variadic_func(args: &[Type], ret: &Type) -> Type {
149 let vec : &[TypeRef] = unsafe { cast::transmute(args) };
150 ty!(llvm::LLVMFunctionType(ret.to_ref(), vec.as_ptr(),
151 args.len() as c_uint, True))
152 }
153
154 pub fn struct_(ccx: &CrateContext, els: &[Type], packed: bool) -> Type {
155 let els : &[TypeRef] = unsafe { cast::transmute(els) };
156 ty!(llvm::LLVMStructTypeInContext(ccx.llcx, els.as_ptr(),
157 els.len() as c_uint,
158 packed as Bool))
159 }
160
161 pub fn named_struct(ccx: &CrateContext, name: &str) -> Type {
162 ty!(name.with_c_str(|s| llvm::LLVMStructCreateNamed(ccx.llcx, s)))
163 }
164
165 pub fn empty_struct(ccx: &CrateContext) -> Type {
166 Type::struct_(ccx, [], false)
167 }
168
169 pub fn vtable(ccx: &CrateContext) -> Type {
170 Type::array(&Type::i8p(ccx).ptr_to(), 1)
171 }
172
173 pub fn generic_glue_fn(cx: &CrateContext) -> Type {
174 match cx.tn.find_type("glue_fn") {
175 Some(ty) => return ty,
176 None => ()
177 }
178
179 let ty = Type::glue_fn(cx, Type::i8p(cx));
180 cx.tn.associate_type("glue_fn", &ty);
181
182 ty
183 }
184
185 pub fn glue_fn(ccx: &CrateContext, t: Type) -> Type {
186 Type::func([t], &Type::void(ccx))
187 }
188
189 pub fn tydesc(ccx: &CrateContext) -> Type {
190 let mut tydesc = Type::named_struct(ccx, "tydesc");
191 let glue_fn_ty = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to();
192
193 let int_ty = Type::int(ccx);
194
195 // Must mirror:
196 //
197 // std::unstable::intrinsics::TyDesc
198
199 let elems = [int_ty, // size
200 int_ty, // align
201 glue_fn_ty, // drop
202 glue_fn_ty, // visit
203 Type::struct_(ccx, [Type::i8p(ccx), Type::int(ccx)], false)]; // name
204 tydesc.set_struct_body(elems, false);
205
206 tydesc
207 }
208
209 pub fn array(ty: &Type, len: u64) -> Type {
210 ty!(llvm::LLVMArrayType(ty.to_ref(), len as c_uint))
211 }
212
213 pub fn vector(ty: &Type, len: u64) -> Type {
214 ty!(llvm::LLVMVectorType(ty.to_ref(), len as c_uint))
215 }
216
217 pub fn vec(ccx: &CrateContext, ty: &Type) -> Type {
218 Type::struct_(ccx,
219 [Type::int(ccx), Type::int(ccx), Type::array(ty, 0)],
220 false)
221 }
222
223 pub fn opaque_vec(ccx: &CrateContext) -> Type {
224 Type::vec(ccx, &Type::i8(ccx))
225 }
226
227 // The box pointed to by @T.
228 pub fn at_box(ccx: &CrateContext, ty: Type) -> Type {
229 Type::struct_(ccx, [
230 ccx.int_type, Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to(),
231 Type::i8p(ccx), Type::i8p(ccx), ty
232 ], false)
233 }
234
235 pub fn opaque_trait(ccx: &CrateContext) -> Type {
236 let vtable = Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to().ptr_to();
237 Type::struct_(ccx, [vtable, Type::i8p(ccx)], false)
238 }
239
240 pub fn kind(&self) -> TypeKind {
241 unsafe {
242 llvm::LLVMGetTypeKind(self.to_ref())
243 }
244 }
245
246 pub fn set_struct_body(&mut self, els: &[Type], packed: bool) {
247 unsafe {
248 let vec : &[TypeRef] = cast::transmute(els);
249 llvm::LLVMStructSetBody(self.to_ref(), vec.as_ptr(),
250 els.len() as c_uint, packed as Bool)
251 }
252 }
253
254 pub fn ptr_to(&self) -> Type {
255 ty!(llvm::LLVMPointerType(self.to_ref(), 0))
256 }
257
258 pub fn is_packed(&self) -> bool {
259 unsafe {
260 llvm::LLVMIsPackedStruct(self.to_ref()) == True
261 }
262 }
263
264 pub fn element_type(&self) -> Type {
265 unsafe {
266 Type::from_ref(llvm::LLVMGetElementType(self.to_ref()))
267 }
268 }
269
270 pub fn array_length(&self) -> uint {
271 unsafe {
272 llvm::LLVMGetArrayLength(self.to_ref()) as uint
273 }
274 }
275
276 pub fn field_types(&self) -> Vec<Type> {
277 unsafe {
278 let n_elts = llvm::LLVMCountStructElementTypes(self.to_ref()) as uint;
279 if n_elts == 0 {
280 return Vec::new();
281 }
282 let mut elts = Vec::from_elem(n_elts, 0 as TypeRef);
283 llvm::LLVMGetStructElementTypes(self.to_ref(), elts.get_mut(0));
284 cast::transmute(elts)
285 }
286 }
287
288 pub fn return_type(&self) -> Type {
289 ty!(llvm::LLVMGetReturnType(self.to_ref()))
290 }
291
292 pub fn func_params(&self) -> Vec<Type> {
293 unsafe {
294 let n_args = llvm::LLVMCountParamTypes(self.to_ref()) as uint;
295 let args = Vec::from_elem(n_args, 0 as TypeRef);
296 llvm::LLVMGetParamTypes(self.to_ref(), args.as_ptr());
297 cast::transmute(args)
298 }
299 }
300
301 pub fn float_width(&self) -> uint {
302 match self.kind() {
303 Float => 32,
304 Double => 64,
305 X86_FP80 => 80,
306 FP128 | PPC_FP128 => 128,
307 _ => fail!("llvm_float_width called on a non-float type")
308 }
309 }
310 }