1 // Copyright 2012-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_camel_case_types)]
12
13 use middle::trans::adt;
14 use middle::trans::common::*;
15 use middle::trans::foreign;
16 use middle::ty;
17 use util::ppaux;
18 use util::ppaux::Repr;
19
20 use middle::trans::type_::Type;
21
22 use syntax::abi;
23 use syntax::ast;
24 use syntax::owned_slice::OwnedSlice;
25
26 pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
27 !type_is_immediate(ccx, arg_ty)
28 }
29
30 pub fn return_uses_outptr(ccx: &CrateContext, ty: ty::t) -> bool {
31 !type_is_immediate(ccx, ty)
32 }
33
34 pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
35 let llty = type_of(ccx, arg_ty);
36 if arg_is_indirect(ccx, arg_ty) {
37 llty.ptr_to()
38 } else {
39 llty
40 }
41 }
42
43 pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
44 inputs: &[ty::t], output: ty::t) -> Type {
45 let mut atys: Vec<Type> = Vec::new();
46
47 // Arg 0: Output pointer.
48 // (if the output type is non-immediate)
49 let use_out_pointer = return_uses_outptr(cx, output);
50 let lloutputtype = type_of(cx, output);
51 if use_out_pointer {
52 atys.push(lloutputtype.ptr_to());
53 }
54
55 // Arg 1: Environment
56 if has_env {
57 atys.push(Type::i8p(cx));
58 }
59
60 // ... then explicit args.
61 let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
62 atys.extend(input_tys);
63
64 // Use the output as the actual return value if it's immediate.
65 if use_out_pointer || return_type_is_void(cx, output) {
66 Type::func(atys.as_slice(), &Type::void(cx))
67 } else {
68 Type::func(atys.as_slice(), &lloutputtype)
69 }
70 }
71
72 // Given a function type and a count of ty params, construct an llvm type
73 pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
74 match ty::get(fty).sty {
75 ty::ty_closure(ref f) => {
76 type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output)
77 }
78 ty::ty_bare_fn(ref f) => {
79 if f.abi == abi::Rust || f.abi == abi::RustIntrinsic {
80 type_of_rust_fn(cx,
81 false,
82 f.sig.inputs.as_slice(),
83 f.sig.output)
84 } else {
85 foreign::lltype_for_foreign_fn(cx, fty)
86 }
87 }
88 _ => {
89 cx.sess().bug("type_of_fn_from_ty given non-closure, non-bare-fn")
90 }
91 }
92 }
93
94 // A "sizing type" is an LLVM type, the size and alignment of which are
95 // guaranteed to be equivalent to what you would get out of `type_of()`. It's
96 // useful because:
97 //
98 // (1) It may be cheaper to compute the sizing type than the full type if all
99 // you're interested in is the size and/or alignment;
100 //
101 // (2) It won't make any recursive calls to determine the structure of the
102 // type behind pointers. This can help prevent infinite loops for
103 // recursive types. For example, enum types rely on this behavior.
104
105 pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
106 match cx.llsizingtypes.borrow().find_copy(&t) {
107 Some(t) => return t,
108 None => ()
109 }
110
111 let llsizingty = match ty::get(t).sty {
112 ty::ty_nil | ty::ty_bot => Type::nil(cx),
113 ty::ty_bool => Type::bool(cx),
114 ty::ty_char => Type::char(cx),
115 ty::ty_int(t) => Type::int_from_ty(cx, t),
116 ty::ty_uint(t) => Type::uint_from_ty(cx, t),
117 ty::ty_float(t) => Type::float_from_ty(cx, t),
118
119 ty::ty_box(..) |
120 ty::ty_uniq(..) |
121 ty::ty_ptr(..) => Type::i8p(cx),
122 ty::ty_rptr(_, mt) => {
123 match ty::get(mt.ty).sty {
124 ty::ty_vec(_, None) | ty::ty_str => {
125 Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false)
126 }
127 _ => Type::i8p(cx),
128 }
129 }
130
131 ty::ty_bare_fn(..) => Type::i8p(cx),
132 ty::ty_closure(..) => Type::struct_(cx, [Type::i8p(cx), Type::i8p(cx)], false),
133 ty::ty_trait(..) => Type::opaque_trait(cx),
134
135 ty::ty_vec(mt, Some(size)) => {
136 Type::array(&sizing_type_of(cx, mt.ty), size as u64)
137 }
138
139 ty::ty_tup(..) | ty::ty_enum(..) => {
140 let repr = adt::represent_type(cx, t);
141 adt::sizing_type_of(cx, &*repr)
142 }
143
144 ty::ty_struct(..) => {
145 if ty::type_is_simd(cx.tcx(), t) {
146 let et = ty::simd_type(cx.tcx(), t);
147 let n = ty::simd_size(cx.tcx(), t);
148 Type::vector(&type_of(cx, et), n as u64)
149 } else {
150 let repr = adt::represent_type(cx, t);
151 adt::sizing_type_of(cx, &*repr)
152 }
153 }
154
155 ty::ty_self(_) | ty::ty_infer(..) | ty::ty_param(..) |
156 ty::ty_err(..) | ty::ty_vec(_, None) | ty::ty_str => {
157 cx.sess().bug(format!("fictitious type {:?} in sizing_type_of()",
158 ty::get(t).sty))
159 }
160 };
161
162 cx.llsizingtypes.borrow_mut().insert(t, llsizingty);
163 llsizingty
164 }
165
166 // NB: If you update this, be sure to update `sizing_type_of()` as well.
167 pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
168 // Check the cache.
169 match cx.lltypes.borrow().find(&t) {
170 Some(&llty) => return llty,
171 None => ()
172 }
173
174 debug!("type_of {} {:?}", t.repr(cx.tcx()), t);
175
176 // Replace any typedef'd types with their equivalent non-typedef
177 // type. This ensures that all LLVM nominal types that contain
178 // Rust types are defined as the same LLVM types. If we don't do
179 // this then, e.g. `Option<{myfield: bool}>` would be a different
180 // type than `Option<myrec>`.
181 let t_norm = ty::normalize_ty(cx.tcx(), t);
182
183 if t != t_norm {
184 let llty = type_of(cx, t_norm);
185 debug!("--> normalized {} {:?} to {} {:?} llty={}",
186 t.repr(cx.tcx()),
187 t,
188 t_norm.repr(cx.tcx()),
189 t_norm,
190 cx.tn.type_to_str(llty));
191 cx.lltypes.borrow_mut().insert(t, llty);
192 return llty;
193 }
194
195 let mut llty = match ty::get(t).sty {
196 ty::ty_nil | ty::ty_bot => Type::nil(cx),
197 ty::ty_bool => Type::bool(cx),
198 ty::ty_char => Type::char(cx),
199 ty::ty_int(t) => Type::int_from_ty(cx, t),
200 ty::ty_uint(t) => Type::uint_from_ty(cx, t),
201 ty::ty_float(t) => Type::float_from_ty(cx, t),
202 ty::ty_enum(did, ref substs) => {
203 // Only create the named struct, but don't fill it in. We
204 // fill it in *after* placing it into the type cache. This
205 // avoids creating more than one copy of the enum when one
206 // of the enum's variants refers to the enum itself.
207 let repr = adt::represent_type(cx, t);
208 let name = llvm_type_name(cx, an_enum, did, substs.tps.as_slice());
209 adt::incomplete_type_of(cx, &*repr, name)
210 }
211 ty::ty_box(typ) => {
212 Type::at_box(cx, type_of(cx, typ)).ptr_to()
213 }
214 ty::ty_uniq(typ) => {
215 match ty::get(typ).sty {
216 ty::ty_vec(mt, None) => Type::vec(cx, &type_of(cx, mt.ty)).ptr_to(),
217 ty::ty_str => Type::vec(cx, &Type::i8(cx)).ptr_to(),
218 _ => type_of(cx, typ).ptr_to(),
219 }
220 }
221 ty::ty_ptr(ref mt) => type_of(cx, mt.ty).ptr_to(),
222 ty::ty_rptr(_, ref mt) => {
223 match ty::get(mt.ty).sty {
224 ty::ty_vec(mt, None) => {
225 let p_ty = type_of(cx, mt.ty).ptr_to();
226 let u_ty = Type::uint_from_ty(cx, ast::TyU);
227 Type::struct_(cx, [p_ty, u_ty], false)
228 }
229 ty::ty_str => {
230 // This means we get a nicer name in the output
231 cx.tn.find_type("str_slice").unwrap()
232 }
233 _ => type_of(cx, mt.ty).ptr_to(),
234 }
235 }
236
237 ty::ty_vec(ref mt, Some(n)) => {
238 Type::array(&type_of(cx, mt.ty), n as u64)
239 }
240
241 ty::ty_bare_fn(_) => {
242 type_of_fn_from_ty(cx, t).ptr_to()
243 }
244 ty::ty_closure(_) => {
245 let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
246 Type::struct_(cx, [fn_ty, Type::i8p(cx)], false)
247 }
248 ty::ty_trait(..) => Type::opaque_trait(cx),
249 ty::ty_tup(..) => {
250 let repr = adt::represent_type(cx, t);
251 adt::type_of(cx, &*repr)
252 }
253 ty::ty_struct(did, ref substs) => {
254 if ty::type_is_simd(cx.tcx(), t) {
255 let et = ty::simd_type(cx.tcx(), t);
256 let n = ty::simd_size(cx.tcx(), t);
257 Type::vector(&type_of(cx, et), n as u64)
258 } else {
259 // Only create the named struct, but don't fill it in. We fill it
260 // in *after* placing it into the type cache. This prevents
261 // infinite recursion with recursive struct types.
262 let repr = adt::represent_type(cx, t);
263 let name = llvm_type_name(cx,
264 a_struct,
265 did,
266 substs.tps.as_slice());
267 adt::incomplete_type_of(cx, &*repr, name)
268 }
269 }
270
271 ty::ty_vec(_, None) => cx.sess().bug("type_of with unsized ty_vec"),
272 ty::ty_str => cx.sess().bug("type_of with unsized (bare) ty_str"),
273 ty::ty_self(..) => cx.sess().unimpl("type_of with ty_self"),
274 ty::ty_infer(..) => cx.sess().bug("type_of with ty_infer"),
275 ty::ty_param(..) => cx.sess().bug("type_of with ty_param"),
276 ty::ty_err(..) => cx.sess().bug("type_of with ty_err")
277 };
278
279 debug!("--> mapped t={} {:?} to llty={}",
280 t.repr(cx.tcx()),
281 t,
282 cx.tn.type_to_str(llty));
283
284 cx.lltypes.borrow_mut().insert(t, llty);
285
286 // If this was an enum or struct, fill in the type now.
287 match ty::get(t).sty {
288 ty::ty_enum(..) | ty::ty_struct(..) if !ty::type_is_simd(cx.tcx(), t) => {
289 let repr = adt::represent_type(cx, t);
290 adt::finish_type_of(cx, &*repr, &mut llty);
291 }
292 _ => ()
293 }
294
295 return llty;
296 }
297
298 // Want refinements! (Or case classes, I guess
299 pub enum named_ty { a_struct, an_enum }
300
301 pub fn llvm_type_name(cx: &CrateContext,
302 what: named_ty,
303 did: ast::DefId,
304 tps: &[ty::t]) -> ~str {
305 let name = match what {
306 a_struct => { "struct" }
307 an_enum => { "enum" }
308 };
309 let tstr = ppaux::parameterized(cx.tcx(), ty::item_path_str(cx.tcx(), did),
310 &ty::NonerasedRegions(OwnedSlice::empty()),
311 tps, did, false);
312 if did.krate == 0 {
313 format!("{}.{}", name, tstr)
314 } else {
315 format!("{}.{}[\\#{}]", name, tstr, did.krate)
316 }
317 }
318
319 pub fn type_of_dtor(ccx: &CrateContext, self_ty: ty::t) -> Type {
320 let self_ty = type_of(ccx, self_ty).ptr_to();
321 Type::func([self_ty], &Type::void(ccx))
322 }
librustc/middle/trans/type_of.rs:25:1-25:1 -fn- definition:
pub fn arg_is_indirect(ccx: &CrateContext, arg_ty: ty::t) -> bool {
!type_is_immediate(ccx, arg_ty)
}
references:- 535: let llty = type_of(ccx, arg_ty);
36: if arg_is_indirect(ccx, arg_ty) {
37: llty.ptr_to()
librustc/middle/trans/base.rs:
1248: datum::Rvalue {
1249: mode: if arg_is_indirect(cx.ccx, t) { ByRef } else { ByValue }
1250: }
librustc/middle/trans/_match.rs:
2066: let arg_ty = node_id_type(bcx, pat.id);
2067: if type_of::arg_is_indirect(bcx.ccx(), arg_ty)
2068: && bcx.sess().opts.debuginfo != FullDebugInfo {
librustc/middle/trans/foreign.rs:
670: let llrust_ty = *tys.llsig.llarg_tys.get(i);
671: let rust_indirect = type_of::arg_is_indirect(ccx, rust_ty);
672: let llforeign_arg_ty = *tys.fn_ty.arg_tys.get(i);
librustc/middle/trans/type_of.rs:33:1-33:1 -fn- definition:
pub fn type_of_explicit_arg(ccx: &CrateContext, arg_ty: ty::t) -> Type {
let llty = type_of(ccx, arg_ty);
if arg_is_indirect(ccx, arg_ty) {
references:- 2librustc/middle/trans/callee.rs:
898: // this could happen due to e.g. subtyping
899: let llformal_arg_ty = type_of::type_of_explicit_arg(ccx, formal_arg_ty);
900: debug!("casting actual type ({}) to match formal ({})",
librustc/middle/trans/type_of.rs:
60: // ... then explicit args.
61: let input_tys = inputs.iter().map(|&arg_ty| type_of_explicit_arg(cx, arg_ty));
62: atys.extend(input_tys);
librustc/middle/trans/type_of.rs:166:73-166:73 -fn- definition:
// NB: If you update this, be sure to update `sizing_type_of()` as well.
pub fn type_of(cx: &CrateContext, t: ty::t) -> Type {
// Check the cache.
references:- 93librustc/middle/trans/base.rs:
librustc/middle/trans/_match.rs:
librustc/middle/trans/closure.rs:
librustc/middle/trans/tvec.rs:
librustc/middle/trans/meth.rs:
librustc/middle/trans/foreign.rs:
librustc/middle/trans/intrinsic.rs:
librustc/middle/trans/reflect.rs:
librustc/middle/trans/debuginfo.rs:
librustc/middle/trans/adt.rs:
librustc/middle/trans/asm.rs:
librustc/middle/trans/glue.rs:
librustc/middle/trans/datum.rs:
librustc/middle/trans/callee.rs:
librustc/middle/trans/expr.rs:
librustc/middle/trans/consts.rs:
librustc/middle/trans/debuginfo.rs:
librustc/middle/trans/type_of.rs:104:1-104:1 -fn- definition:
pub fn sizing_type_of(cx: &CrateContext, t: ty::t) -> Type {
match cx.llsizingtypes.borrow().find_copy(&t) {
Some(t) => return t,
references:- 9135: ty::ty_vec(mt, Some(size)) => {
136: Type::array(&sizing_type_of(cx, mt.ty), size as u64)
137: }
librustc/middle/trans/adt.rs:
298: fn mk_struct(cx: &CrateContext, tys: &[ty::t], packed: bool) -> Struct {
299: let lltys = tys.iter().map(|&ty| type_of::sizing_type_of(cx, ty)).collect::<Vec<_>>();
300: let llty_rec = Type::struct_(cx, lltys.as_slice(), packed);
--
790: for &ty in st.fields.iter() {
791: let llty = type_of::sizing_type_of(ccx, ty);
792: if !st.packed {
librustc/middle/trans/glue.rs:
88: _ => {
89: let llty = sizing_type_of(ccx, typ);
90: // Unique boxes do not allocate for zero-size types. The standard
librustc/middle/trans/common.rs:
73: ty::ty_struct(..) | ty::ty_enum(..) | ty::ty_tup(..) => {
74: let llty = sizing_type_of(ccx, ty);
75: llsize_of_alloc(ccx, llty) <= llsize_of_alloc(ccx, ccx.int_type)
--
87: use middle::trans::type_of::sizing_type_of;
88: let llty = sizing_type_of(ccx, ty);
89: llsize_of_alloc(ccx, llty) == 0
librustc/middle/trans/consts.rs:
273: let llty = type_of::sizing_type_of(cx, ety_adjusted);
274: let csize = machine::llsize_of_alloc(cx, val_ty(llconst));
librustc/middle/trans/adt.rs:
771: // field; see #8506.
772: C_null(type_of::sizing_type_of(ccx, ty))
773: }).collect::<Vec<ValueRef>>();
librustc/middle/trans/type_of.rs:72:74-72:74 -fn- definition:
// Given a function type and a count of ty params, construct an llvm type
pub fn type_of_fn_from_ty(cx: &CrateContext, fty: ty::t) -> Type {
match ty::get(fty).sty {
references:- 6241: ty::ty_bare_fn(_) => {
242: type_of_fn_from_ty(cx, t).ptr_to()
243: }
244: ty::ty_closure(_) => {
245: let fn_ty = type_of_fn_from_ty(cx, t).ptr_to();
246: Type::struct_(cx, [fn_ty, Type::i8p(cx)], false)
librustc/middle/trans/meth.rs:
213: let callee_ty = node_id_type(bcx, expr_id);
214: let llty = type_of_fn_from_ty(ccx, callee_ty).ptr_to();
215: PointerCast(bcx, llfn, llty)
librustc/middle/trans/callee.rs:
444: // other weird situations. Annoying.
445: let llty = type_of::type_of_fn_from_ty(ccx, fn_tpt.ty);
446: let llptrty = llty.ptr_to();
librustc/middle/trans/base.rs:
860: let cconv = c.unwrap_or(lib::llvm::CCallConv);
861: let llty = type_of_fn_from_ty(ccx, t);
862: get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod,
librustc/middle/trans/type_of.rs:29:1-29:1 -fn- definition:
pub fn return_uses_outptr(ccx: &CrateContext, ty: ty::t) -> bool {
!type_is_immediate(ccx, ty)
}
references:- 1148: // (if the output type is non-immediate)
49: let use_out_pointer = return_uses_outptr(cx, output);
50: let lloutputtype = type_of(cx, output);
librustc/middle/trans/base.rs:
245: let uses_outptr = type_of::return_uses_outptr(ccx, output);
246: let offset = if uses_outptr { 1 } else { 0 };
--
1117: unsafe {
1118: if type_of::return_uses_outptr(fcx.ccx, output_type) {
1119: llvm::LLVMGetParam(fcx.llfn, 0)
--
1164: };
1165: let uses_outptr = type_of::return_uses_outptr(ccx, substd_output_type);
1166: let debug_context = debuginfo::create_function_debug_context(ccx, id, param_substs, llfndecl);
librustc/middle/trans/foreign.rs:
614: let rust_uses_outptr =
615: type_of::return_uses_outptr(ccx, tys.fn_sig.output);
616: let return_alloca: Option<ValueRef>;
--
824: llret_ty: llret_ty,
825: sret: type_of::return_uses_outptr(ccx, fn_sig.output),
826: }
librustc/middle/trans/callee.rs:
618: // return type, otherwise push "undef".
619: if type_of::return_uses_outptr(ccx, ret_ty) {
620: llargs.push(opt_llretslot.unwrap());
--
735: None => {
736: assert!(!type_of::return_uses_outptr(bcx.ccx(), ret_ty));
737: }
librustc/middle/trans/type_of.rs:42:1-42:1 -fn- definition:
pub fn type_of_rust_fn(cx: &CrateContext, has_env: bool,
inputs: &[ty::t], output: ty::t) -> Type {
let mut atys: Vec<Type> = Vec::new();
references:- 475: ty::ty_closure(ref f) => {
76: type_of_rust_fn(cx, true, f.sig.inputs.as_slice(), f.sig.output)
77: }
librustc/middle/trans/base.rs:
242: let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
243: let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
librustc/middle/trans/meth.rs:
406: ty::ty_bare_fn(ref f) if f.abi == Rust => {
407: type_of_rust_fn(ccx, true, f.sig.inputs.slice_from(1), f.sig.output)
408: }
librustc/middle/trans/type_of.rs:
79: if f.abi == abi::Rust || f.abi == abi::RustIntrinsic {
80: type_of_rust_fn(cx,
81: false,
librustc/middle/trans/type_of.rs:300:1-300:1 -fn- definition:
pub fn llvm_type_name(cx: &CrateContext,
what: named_ty,
did: ast::DefId,
references:- 2207: let repr = adt::represent_type(cx, t);
208: let name = llvm_type_name(cx, an_enum, did, substs.tps.as_slice());
209: adt::incomplete_type_of(cx, &*repr, name)
--
262: let repr = adt::represent_type(cx, t);
263: let name = llvm_type_name(cx,
264: a_struct,