1 // Copyright 2012-2014 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 // trans.rs: Translate the completed AST to the LLVM IR.
12 //
13 // Some functions here, such as trans_block and trans_expr, return a value --
14 // the result of the translation to LLVM -- while others, such as trans_fn,
15 // trans_impl, and trans_item, are called only for the side effect of adding a
16 // particular definition to the LLVM IR output we're producing.
17 //
18 // Hopefully useful general knowledge about trans:
19 //
20 // * There's no way to find out the ty::t type of a ValueRef. Doing so
21 // would be "trying to get the eggs out of an omelette" (credit:
22 // pcwalton). You can, instead, find out its TypeRef by calling val_ty,
23 // but one TypeRef corresponds to many `ty::t`s; for instance, tup(int, int,
24 // int) and rec(x=int, y=int, z=int) will have the same TypeRef.
25
26 #![allow(non_camel_case_types)]
27
28 use back::link::{mangle_exported_name};
29 use back::{link, abi};
30 use driver::session;
31 use driver::session::{Session, NoDebugInfo, FullDebugInfo};
32 use driver::driver::OutputFilenames;
33 use driver::driver::{CrateAnalysis, CrateTranslation};
34 use lib::llvm::{ModuleRef, ValueRef, BasicBlockRef};
35 use lib::llvm::{llvm, Vector};
36 use lib;
37 use metadata::{csearch, encoder};
38 use middle::astencode;
39 use middle::lang_items::{LangItem, ExchangeMallocFnLangItem, StartFnLangItem};
40 use middle::trans::_match;
41 use middle::trans::adt;
42 use middle::trans::build::*;
43 use middle::trans::builder::{Builder, noname};
44 use middle::trans::callee;
45 use middle::trans::cleanup;
46 use middle::trans::cleanup::CleanupMethods;
47 use middle::trans::common::*;
48 use middle::trans::consts;
49 use middle::trans::controlflow;
50 use middle::trans::datum;
51 // use middle::trans::datum::{Datum, Lvalue, Rvalue, ByRef, ByValue};
52 use middle::trans::debuginfo;
53 use middle::trans::expr;
54 use middle::trans::foreign;
55 use middle::trans::glue;
56 use middle::trans::inline;
57 use middle::trans::machine;
58 use middle::trans::machine::{llalign_of_min, llsize_of};
59 use middle::trans::meth;
60 use middle::trans::monomorphize;
61 use middle::trans::tvec;
62 use middle::trans::type_::Type;
63 use middle::trans::type_of;
64 use middle::trans::type_of::*;
65 use middle::trans::value::Value;
66 use middle::ty;
67 use middle::typeck;
68 use util::common::indenter;
69 use util::ppaux::{Repr, ty_to_str};
70 use util::sha2::Sha256;
71 use util::nodemap::NodeMap;
72
73 use arena::TypedArena;
74 use libc::c_uint;
75 use std::c_str::ToCStr;
76 use std::cell::{Cell, RefCell};
77 use std::rc::Rc;
78 use syntax::abi::{X86, X86_64, Arm, Mips, Rust, RustIntrinsic};
79 use syntax::ast_util::{local_def, is_local};
80 use syntax::attr::AttrMetaMethods;
81 use syntax::attr;
82 use syntax::codemap::Span;
83 use syntax::parse::token::InternedString;
84 use syntax::visit::Visitor;
85 use syntax::visit;
86 use syntax::{ast, ast_util, ast_map};
87
88 use time;
89
90 local_data_key!(task_local_insn_key: RefCell<Vec<&'static str>>)
91
92 pub fn with_insn_ctxt(blk: |&[&'static str]|) {
93 match task_local_insn_key.get() {
94 Some(ctx) => blk(ctx.borrow().as_slice()),
95 None => ()
96 }
97 }
98
99 pub fn init_insn_ctxt() {
100 task_local_insn_key.replace(Some(RefCell::new(Vec::new())));
101 }
102
103 pub struct _InsnCtxt { _x: () }
104
105 #[unsafe_destructor]
106 impl Drop for _InsnCtxt {
107 fn drop(&mut self) {
108 match task_local_insn_key.get() {
109 Some(ctx) => { ctx.borrow_mut().pop(); }
110 None => {}
111 }
112 }
113 }
114
115 pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
116 debug!("new InsnCtxt: {}", s);
117 match task_local_insn_key.get() {
118 Some(ctx) => ctx.borrow_mut().push(s),
119 None => {}
120 }
121 _InsnCtxt { _x: () }
122 }
123
124 pub struct StatRecorder<'a> {
125 ccx: &'a CrateContext,
126 name: Option<~str>,
127 start: u64,
128 istart: uint,
129 }
130
131 impl<'a> StatRecorder<'a> {
132 pub fn new(ccx: &'a CrateContext, name: ~str) -> StatRecorder<'a> {
133 let start = if ccx.sess().trans_stats() {
134 time::precise_time_ns()
135 } else {
136 0
137 };
138 let istart = ccx.stats.n_llvm_insns.get();
139 StatRecorder {
140 ccx: ccx,
141 name: Some(name),
142 start: start,
143 istart: istart,
144 }
145 }
146 }
147
148 #[unsafe_destructor]
149 impl<'a> Drop for StatRecorder<'a> {
150 fn drop(&mut self) {
151 if self.ccx.sess().trans_stats() {
152 let end = time::precise_time_ns();
153 let elapsed = ((end - self.start) / 1_000_000) as uint;
154 let iend = self.ccx.stats.n_llvm_insns.get();
155 self.ccx.stats.fn_stats.borrow_mut().push((self.name.take_unwrap(),
156 elapsed,
157 iend - self.istart));
158 self.ccx.stats.n_fns.set(self.ccx.stats.n_fns.get() + 1);
159 // Reset LLVM insn count to avoid compound costs.
160 self.ccx.stats.n_llvm_insns.set(self.istart);
161 }
162 }
163 }
164
165 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
166 fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
167 ty: Type, output: ty::t) -> ValueRef {
168 let llfn: ValueRef = name.with_c_str(|buf| {
169 unsafe {
170 llvm::LLVMGetOrInsertFunction(llmod, buf, ty.to_ref())
171 }
172 });
173
174 match ty::get(output).sty {
175 // functions returning bottom may unwind, but can never return normally
176 ty::ty_bot => {
177 unsafe {
178 llvm::LLVMAddFunctionAttr(llfn, lib::llvm::NoReturnAttribute as c_uint)
179 }
180 }
181 // `~` pointer return values never alias because ownership is transferred
182 ty::ty_uniq(..) // | ty::ty_trait(_, _, ty::UniqTraitStore, _, _)
183 => {
184 unsafe {
185 llvm::LLVMAddReturnAttribute(llfn, lib::llvm::NoAliasAttribute as c_uint);
186 }
187 }
188 _ => {}
189 }
190
191 lib::llvm::SetFunctionCallConv(llfn, cc);
192 // Function addresses in Rust are never significant, allowing functions to be merged.
193 lib::llvm::SetUnnamedAddr(llfn, true);
194 set_split_stack(llfn);
195
196 llfn
197 }
198
199 // only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
200 pub fn decl_cdecl_fn(llmod: ModuleRef,
201 name: &str,
202 ty: Type,
203 output: ty::t) -> ValueRef {
204 decl_fn(llmod, name, lib::llvm::CCallConv, ty, output)
205 }
206
207 // only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
208 pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef,
209 name: &str, cc: lib::llvm::CallConv,
210 ty: Type, output: ty::t) -> ValueRef {
211 match externs.find_equiv(&name) {
212 Some(n) => return *n,
213 None => {}
214 }
215 let f = decl_fn(llmod, name, cc, ty, output);
216 externs.insert(name.to_owned(), f);
217 f
218 }
219
220 fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
221 name: &str, did: ast::DefId) -> ValueRef {
222 match ccx.externs.borrow().find_equiv(&name) {
223 Some(n) => return *n,
224 None => ()
225 }
226
227 let f = decl_rust_fn(ccx, false, inputs, output, name);
228 csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
229 set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr(x))
230 .collect::<Vec<_>>().as_slice(), f)
231 });
232
233 ccx.externs.borrow_mut().insert(name.to_owned(), f);
234 f
235 }
236
237 pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
238 inputs: &[ty::t], output: ty::t,
239 name: &str) -> ValueRef {
240 use middle::ty::{BrAnon, ReLateBound};
241
242 let llfty = type_of_rust_fn(ccx, has_env, inputs, output);
243 let llfn = decl_cdecl_fn(ccx.llmod, name, llfty, output);
244
245 let uses_outptr = type_of::return_uses_outptr(ccx, output);
246 let offset = if uses_outptr { 1 } else { 0 };
247 let offset = if has_env { offset + 1 } else { offset };
248
249 for (i, &arg_ty) in inputs.iter().enumerate() {
250 let llarg = unsafe { llvm::LLVMGetParam(llfn, (offset + i) as c_uint) };
251 match ty::get(arg_ty).sty {
252 // `~` pointer parameters never alias because ownership is transferred
253 ty::ty_uniq(..) => {
254 unsafe {
255 llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
256 }
257 }
258 // `&mut` pointer parameters never alias other parameters, or mutable global data
259 ty::ty_rptr(_, mt) if mt.mutbl == ast::MutMutable => {
260 unsafe {
261 llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
262 }
263 }
264 // When a reference in an argument has no named lifetime, it's impossible for that
265 // reference to escape this function (returned or stored beyond the call by a closure).
266 ty::ty_rptr(ReLateBound(_, BrAnon(_)), _) => {
267 debug!("marking argument of {} as nocapture because of anonymous lifetime", name);
268 unsafe {
269 llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
270 }
271 }
272 _ => {
273 // For non-immediate arguments the callee gets its own copy of
274 // the value on the stack, so there are no aliases
275 if !type_is_immediate(ccx, arg_ty) {
276 unsafe {
277 llvm::LLVMAddAttribute(llarg, lib::llvm::NoAliasAttribute as c_uint);
278 llvm::LLVMAddAttribute(llarg, lib::llvm::NoCaptureAttribute as c_uint);
279 }
280 }
281 }
282 }
283 }
284
285 // The out pointer will never alias with any other pointers, as the object only exists at a
286 // language level after the call. It can also be tagged with SRet to indicate that it is
287 // guaranteed to point to a usable block of memory for the type.
288 if uses_outptr {
289 unsafe {
290 let outptr = llvm::LLVMGetParam(llfn, 0);
291 llvm::LLVMAddAttribute(outptr, lib::llvm::StructRetAttribute as c_uint);
292 llvm::LLVMAddAttribute(outptr, lib::llvm::NoAliasAttribute as c_uint);
293 }
294 }
295
296 llfn
297 }
298
299 pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
300 inputs: &[ty::t], output: ty::t,
301 name: &str) -> ValueRef {
302 let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
303 lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
304 llfn
305 }
306
307 pub fn get_extern_const(externs: &mut ExternMap, llmod: ModuleRef,
308 name: &str, ty: Type) -> ValueRef {
309 match externs.find_equiv(&name) {
310 Some(n) => return *n,
311 None => ()
312 }
313 unsafe {
314 let c = name.with_c_str(|buf| {
315 llvm::LLVMAddGlobal(llmod, ty.to_ref(), buf)
316 });
317 externs.insert(name.to_owned(), c);
318 return c;
319 }
320 }
321
322 // Returns a pointer to the body for the box. The box may be an opaque
323 // box. The result will be casted to the type of body_t, if it is statically
324 // known.
325 pub fn at_box_body(bcx: &Block, body_t: ty::t, boxptr: ValueRef) -> ValueRef {
326 let _icx = push_ctxt("at_box_body");
327 let ccx = bcx.ccx();
328 let ty = Type::at_box(ccx, type_of(ccx, body_t));
329 let boxptr = PointerCast(bcx, boxptr, ty.ptr_to());
330 GEPi(bcx, boxptr, [0u, abi::box_field_body])
331 }
332
333 fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
334 match bcx.tcx().lang_items.require(it) {
335 Ok(id) => id,
336 Err(s) => {
337 bcx.sess().fatal(format!("allocation of `{}` {}",
338 bcx.ty_to_str(info_ty), s));
339 }
340 }
341 }
342
343 // The following malloc_raw_dyn* functions allocate a box to contain
344 // a given type, but with a potentially dynamic size.
345
346 pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
347 ptr_ty: ty::t,
348 size: ValueRef)
349 -> Result<'a> {
350 let _icx = push_ctxt("malloc_raw_exchange");
351 let ccx = bcx.ccx();
352
353 // Allocate space:
354 let r = callee::trans_lang_call(bcx,
355 require_alloc_fn(bcx, ptr_ty, ExchangeMallocFnLangItem),
356 [size],
357 None);
358
359 let llty_ptr = type_of::type_of(ccx, ptr_ty);
360 Result::new(r.bcx, PointerCast(r.bcx, r.val, llty_ptr))
361 }
362
363 pub fn malloc_raw_dyn_managed<'a>(
364 bcx: &'a Block<'a>,
365 t: ty::t,
366 alloc_fn: LangItem,
367 size: ValueRef)
368 -> Result<'a> {
369 let _icx = push_ctxt("malloc_raw_managed");
370 let ccx = bcx.ccx();
371
372 let langcall = require_alloc_fn(bcx, t, alloc_fn);
373
374 // Grab the TypeRef type of box_ptr_ty.
375 let box_ptr_ty = ty::mk_box(bcx.tcx(), t);
376 let llty = type_of(ccx, box_ptr_ty);
377 let llalign = C_uint(ccx, llalign_of_min(ccx, llty) as uint);
378
379 // Allocate space:
380 let drop_glue = glue::get_drop_glue(ccx, t);
381 let r = callee::trans_lang_call(
382 bcx,
383 langcall,
384 [
385 PointerCast(bcx, drop_glue, Type::glue_fn(ccx, Type::i8p(ccx)).ptr_to()),
386 size,
387 llalign
388 ],
389 None);
390 Result::new(r.bcx, PointerCast(r.bcx, r.val, llty))
391 }
392
393 // Type descriptor and type glue stuff
394
395 pub fn get_tydesc(ccx: &CrateContext, t: ty::t) -> Rc<tydesc_info> {
396 match ccx.tydescs.borrow().find(&t) {
397 Some(inf) => return inf.clone(),
398 _ => { }
399 }
400
401 ccx.stats.n_static_tydescs.set(ccx.stats.n_static_tydescs.get() + 1u);
402 let inf = Rc::new(glue::declare_tydesc(ccx, t));
403
404 ccx.tydescs.borrow_mut().insert(t, inf.clone());
405 inf
406 }
407
408 #[allow(dead_code)] // useful
409 pub fn set_optimize_for_size(f: ValueRef) {
410 lib::llvm::SetFunctionAttribute(f, lib::llvm::OptimizeForSizeAttribute)
411 }
412
413 pub fn set_no_inline(f: ValueRef) {
414 lib::llvm::SetFunctionAttribute(f, lib::llvm::NoInlineAttribute)
415 }
416
417 #[allow(dead_code)] // useful
418 pub fn set_no_unwind(f: ValueRef) {
419 lib::llvm::SetFunctionAttribute(f, lib::llvm::NoUnwindAttribute)
420 }
421
422 // Tell LLVM to emit the information necessary to unwind the stack for the
423 // function f.
424 pub fn set_uwtable(f: ValueRef) {
425 lib::llvm::SetFunctionAttribute(f, lib::llvm::UWTableAttribute)
426 }
427
428 pub fn set_inline_hint(f: ValueRef) {
429 lib::llvm::SetFunctionAttribute(f, lib::llvm::InlineHintAttribute)
430 }
431
432 pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
433 use syntax::attr::*;
434 // Set the inline hint if there is one
435 match find_inline_attr(attrs) {
436 InlineHint => set_inline_hint(llfn),
437 InlineAlways => set_always_inline(llfn),
438 InlineNever => set_no_inline(llfn),
439 InlineNone => { /* fallthrough */ }
440 }
441
442 // Add the no-split-stack attribute if requested
443 if contains_name(attrs, "no_split_stack") {
444 unset_split_stack(llfn);
445 }
446
447 if contains_name(attrs, "cold") {
448 unsafe { llvm::LLVMAddColdAttribute(llfn) }
449 }
450 }
451
452 pub fn set_always_inline(f: ValueRef) {
453 lib::llvm::SetFunctionAttribute(f, lib::llvm::AlwaysInlineAttribute)
454 }
455
456 pub fn set_split_stack(f: ValueRef) {
457 "split-stack".with_c_str(|buf| {
458 unsafe { llvm::LLVMAddFunctionAttrString(f, buf); }
459 })
460 }
461
462 pub fn unset_split_stack(f: ValueRef) {
463 "split-stack".with_c_str(|buf| {
464 unsafe { llvm::LLVMRemoveFunctionAttrString(f, buf); }
465 })
466 }
467
468 // Double-check that we never ask LLVM to declare the same symbol twice. It
469 // silently mangles such symbols, breaking our linkage model.
470 pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: ~str) {
471 if ccx.all_llvm_symbols.borrow().contains(&sym) {
472 ccx.sess().bug("duplicate LLVM symbol: ".to_owned() + sym);
473 }
474 ccx.all_llvm_symbols.borrow_mut().insert(sym);
475 }
476
477
478 pub fn get_res_dtor(ccx: &CrateContext,
479 did: ast::DefId,
480 parent_id: ast::DefId,
481 substs: &[ty::t])
482 -> ValueRef {
483 let _icx = push_ctxt("trans_res_dtor");
484 let did = if did.krate != ast::LOCAL_CRATE {
485 inline::maybe_instantiate_inline(ccx, did)
486 } else {
487 did
488 };
489 if !substs.is_empty() {
490 assert_eq!(did.krate, ast::LOCAL_CRATE);
491 let tsubsts = ty::substs {
492 regions: ty::ErasedRegions,
493 self_ty: None,
494 tps: Vec::from_slice(substs),
495 };
496
497 let vtables = typeck::check::vtable::trans_resolve_method(ccx.tcx(), did.node, &tsubsts);
498 let (val, _) = monomorphize::monomorphic_fn(ccx, did, &tsubsts, vtables, None, None);
499
500 val
501 } else if did.krate == ast::LOCAL_CRATE {
502 get_item_val(ccx, did.node)
503 } else {
504 let tcx = ccx.tcx();
505 let name = csearch::get_symbol(&ccx.sess().cstore, did);
506 let class_ty = ty::subst_tps(tcx,
507 substs,
508 None,
509 ty::lookup_item_type(tcx, parent_id).ty);
510 let llty = type_of_dtor(ccx, class_ty);
511
512 get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod, name,
513 lib::llvm::CCallConv, llty, ty::mk_nil())
514 }
515 }
516
517 // Structural comparison: a rather involved form of glue.
518 pub fn maybe_name_value(cx: &CrateContext, v: ValueRef, s: &str) {
519 if cx.sess().opts.cg.save_temps {
520 s.with_c_str(|buf| {
521 unsafe {
522 llvm::LLVMSetValueName(v, buf)
523 }
524 })
525 }
526 }
527
528
529 // Used only for creating scalar comparison glue.
530 pub enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
531
532 // NB: This produces an i1, not a Rust bool (i8).
533 pub fn compare_scalar_types<'a>(
534 cx: &'a Block<'a>,
535 lhs: ValueRef,
536 rhs: ValueRef,
537 t: ty::t,
538 op: ast::BinOp)
539 -> Result<'a> {
540 let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op));
541
542 match ty::get(t).sty {
543 ty::ty_nil => f(nil_type),
544 ty::ty_bool | ty::ty_ptr(_) |
545 ty::ty_uint(_) | ty::ty_char => f(unsigned_int),
546 ty::ty_int(_) => f(signed_int),
547 ty::ty_float(_) => f(floating_point),
548 // Should never get here, because t is scalar.
549 _ => cx.sess().bug("non-scalar type passed to compare_scalar_types")
550 }
551 }
552
553
554 // A helper function to do the actual comparison of scalar values.
555 pub fn compare_scalar_values<'a>(
556 cx: &'a Block<'a>,
557 lhs: ValueRef,
558 rhs: ValueRef,
559 nt: scalar_type,
560 op: ast::BinOp)
561 -> ValueRef {
562 let _icx = push_ctxt("compare_scalar_values");
563 fn die(cx: &Block) -> ! {
564 cx.sess().bug("compare_scalar_values: must be a comparison operator");
565 }
566 match nt {
567 nil_type => {
568 // We don't need to do actual comparisons for nil.
569 // () == () holds but () < () does not.
570 match op {
571 ast::BiEq | ast::BiLe | ast::BiGe => return C_i1(cx.ccx(), true),
572 ast::BiNe | ast::BiLt | ast::BiGt => return C_i1(cx.ccx(), false),
573 // refinements would be nice
574 _ => die(cx)
575 }
576 }
577 floating_point => {
578 let cmp = match op {
579 ast::BiEq => lib::llvm::RealOEQ,
580 ast::BiNe => lib::llvm::RealUNE,
581 ast::BiLt => lib::llvm::RealOLT,
582 ast::BiLe => lib::llvm::RealOLE,
583 ast::BiGt => lib::llvm::RealOGT,
584 ast::BiGe => lib::llvm::RealOGE,
585 _ => die(cx)
586 };
587 return FCmp(cx, cmp, lhs, rhs);
588 }
589 signed_int => {
590 let cmp = match op {
591 ast::BiEq => lib::llvm::IntEQ,
592 ast::BiNe => lib::llvm::IntNE,
593 ast::BiLt => lib::llvm::IntSLT,
594 ast::BiLe => lib::llvm::IntSLE,
595 ast::BiGt => lib::llvm::IntSGT,
596 ast::BiGe => lib::llvm::IntSGE,
597 _ => die(cx)
598 };
599 return ICmp(cx, cmp, lhs, rhs);
600 }
601 unsigned_int => {
602 let cmp = match op {
603 ast::BiEq => lib::llvm::IntEQ,
604 ast::BiNe => lib::llvm::IntNE,
605 ast::BiLt => lib::llvm::IntULT,
606 ast::BiLe => lib::llvm::IntULE,
607 ast::BiGt => lib::llvm::IntUGT,
608 ast::BiGe => lib::llvm::IntUGE,
609 _ => die(cx)
610 };
611 return ICmp(cx, cmp, lhs, rhs);
612 }
613 }
614 }
615
616 pub fn compare_simd_types(
617 cx: &Block,
618 lhs: ValueRef,
619 rhs: ValueRef,
620 t: ty::t,
621 size: uint,
622 op: ast::BinOp)
623 -> ValueRef {
624 match ty::get(t).sty {
625 ty::ty_float(_) => {
626 // The comparison operators for floating point vectors are challenging.
627 // LLVM outputs a `< size x i1 >`, but if we perform a sign extension
628 // then bitcast to a floating point vector, the result will be `-NaN`
629 // for each truth value. Because of this they are unsupported.
630 cx.sess().bug("compare_simd_types: comparison operators \
631 not supported for floating point SIMD types")
632 },
633 ty::ty_uint(_) | ty::ty_int(_) => {
634 let cmp = match op {
635 ast::BiEq => lib::llvm::IntEQ,
636 ast::BiNe => lib::llvm::IntNE,
637 ast::BiLt => lib::llvm::IntSLT,
638 ast::BiLe => lib::llvm::IntSLE,
639 ast::BiGt => lib::llvm::IntSGT,
640 ast::BiGe => lib::llvm::IntSGE,
641 _ => cx.sess().bug("compare_simd_types: must be a comparison operator"),
642 };
643 let return_ty = Type::vector(&type_of(cx.ccx(), t), size as u64);
644 // LLVM outputs an `< size x i1 >`, so we need to perform a sign extension
645 // to get the correctly sized type. This will compile to a single instruction
646 // once the IR is converted to assembly if the SIMD instruction is supported
647 // by the target architecture.
648 SExt(cx, ICmp(cx, cmp, lhs, rhs), return_ty)
649 },
650 _ => cx.sess().bug("compare_simd_types: invalid SIMD type"),
651 }
652 }
653
654 pub type val_and_ty_fn<'r,'b> =
655 |&'b Block<'b>, ValueRef, ty::t|: 'r -> &'b Block<'b>;
656
657 // Iterates through the elements of a structural type.
658 pub fn iter_structural_ty<'r,
659 'b>(
660 cx: &'b Block<'b>,
661 av: ValueRef,
662 t: ty::t,
663 f: val_and_ty_fn<'r,'b>)
664 -> &'b Block<'b> {
665 let _icx = push_ctxt("iter_structural_ty");
666
667 fn iter_variant<'r,
668 'b>(
669 cx: &'b Block<'b>,
670 repr: &adt::Repr,
671 av: ValueRef,
672 variant: &ty::VariantInfo,
673 tps: &[ty::t],
674 f: val_and_ty_fn<'r,'b>)
675 -> &'b Block<'b> {
676 let _icx = push_ctxt("iter_variant");
677 let tcx = cx.tcx();
678 let mut cx = cx;
679
680 for (i, &arg) in variant.args.iter().enumerate() {
681 cx = f(cx,
682 adt::trans_field_ptr(cx, repr, av, variant.disr_val, i),
683 ty::subst_tps(tcx, tps, None, arg));
684 }
685 return cx;
686 }
687
688 let mut cx = cx;
689 match ty::get(t).sty {
690 ty::ty_struct(..) => {
691 let repr = adt::represent_type(cx.ccx(), t);
692 expr::with_field_tys(cx.tcx(), t, None, |discr, field_tys| {
693 for (i, field_ty) in field_tys.iter().enumerate() {
694 let llfld_a = adt::trans_field_ptr(cx, &*repr, av, discr, i);
695 cx = f(cx, llfld_a, field_ty.mt.ty);
696 }
697 })
698 }
699 ty::ty_vec(_, Some(n)) => {
700 let unit_ty = ty::sequence_element_type(cx.tcx(), t);
701 let (base, len) = tvec::get_fixed_base_and_byte_len(cx, av, unit_ty, n);
702 cx = tvec::iter_vec_raw(cx, base, unit_ty, len, f);
703 }
704 ty::ty_tup(ref args) => {
705 let repr = adt::represent_type(cx.ccx(), t);
706 for (i, arg) in args.iter().enumerate() {
707 let llfld_a = adt::trans_field_ptr(cx, &*repr, av, 0, i);
708 cx = f(cx, llfld_a, *arg);
709 }
710 }
711 ty::ty_enum(tid, ref substs) => {
712 let fcx = cx.fcx;
713 let ccx = fcx.ccx;
714
715 let repr = adt::represent_type(ccx, t);
716 let variants = ty::enum_variants(ccx.tcx(), tid);
717 let n_variants = (*variants).len();
718
719 // NB: we must hit the discriminant first so that structural
720 // comparison know not to proceed when the discriminants differ.
721
722 match adt::trans_switch(cx, &*repr, av) {
723 (_match::single, None) => {
724 cx = iter_variant(cx, &*repr, av, &**variants.get(0),
725 substs.tps.as_slice(), f);
726 }
727 (_match::switch, Some(lldiscrim_a)) => {
728 cx = f(cx, lldiscrim_a, ty::mk_int());
729 let unr_cx = fcx.new_temp_block("enum-iter-unr");
730 Unreachable(unr_cx);
731 let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb,
732 n_variants);
733 let next_cx = fcx.new_temp_block("enum-iter-next");
734
735 for variant in (*variants).iter() {
736 let variant_cx =
737 fcx.new_temp_block("enum-iter-variant-".to_owned() +
738 variant.disr_val.to_str());
739 match adt::trans_case(cx, &*repr, variant.disr_val) {
740 _match::single_result(r) => {
741 AddCase(llswitch, r.val, variant_cx.llbb)
742 }
743 _ => ccx.sess().unimpl("value from adt::trans_case \
744 in iter_structural_ty")
745 }
746 let variant_cx =
747 iter_variant(variant_cx,
748 &*repr,
749 av,
750 &**variant,
751 substs.tps.as_slice(),
752 |x,y,z| f(x,y,z));
753 Br(variant_cx, next_cx.llbb);
754 }
755 cx = next_cx;
756 }
757 _ => ccx.sess().unimpl("value from adt::trans_switch \
758 in iter_structural_ty")
759 }
760 }
761 _ => cx.sess().unimpl("type in iter_structural_ty")
762 }
763 return cx;
764 }
765
766 pub fn cast_shift_expr_rhs<'a>(
767 cx: &'a Block<'a>,
768 op: ast::BinOp,
769 lhs: ValueRef,
770 rhs: ValueRef)
771 -> ValueRef {
772 cast_shift_rhs(op, lhs, rhs,
773 |a,b| Trunc(cx, a, b),
774 |a,b| ZExt(cx, a, b))
775 }
776
777 pub fn cast_shift_const_rhs(op: ast::BinOp,
778 lhs: ValueRef, rhs: ValueRef) -> ValueRef {
779 cast_shift_rhs(op, lhs, rhs,
780 |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) },
781 |a, b| unsafe { llvm::LLVMConstZExt(a, b.to_ref()) })
782 }
783
784 pub fn cast_shift_rhs(op: ast::BinOp,
785 lhs: ValueRef,
786 rhs: ValueRef,
787 trunc: |ValueRef, Type| -> ValueRef,
788 zext: |ValueRef, Type| -> ValueRef)
789 -> ValueRef {
790 // Shifts may have any size int on the rhs
791 unsafe {
792 if ast_util::is_shift_binop(op) {
793 let mut rhs_llty = val_ty(rhs);
794 let mut lhs_llty = val_ty(lhs);
795 if rhs_llty.kind() == Vector { rhs_llty = rhs_llty.element_type() }
796 if lhs_llty.kind() == Vector { lhs_llty = lhs_llty.element_type() }
797 let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty.to_ref());
798 let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty.to_ref());
799 if lhs_sz < rhs_sz {
800 trunc(rhs, lhs_llty)
801 } else if lhs_sz > rhs_sz {
802 // FIXME (#1877: If shifting by negative
803 // values becomes not undefined then this is wrong.
804 zext(rhs, lhs_llty)
805 } else {
806 rhs
807 }
808 } else {
809 rhs
810 }
811 }
812 }
813
814 pub fn fail_if_zero<'a>(
815 cx: &'a Block<'a>,
816 span: Span,
817 divrem: ast::BinOp,
818 rhs: ValueRef,
819 rhs_t: ty::t)
820 -> &'a Block<'a> {
821 let text = if divrem == ast::BiDiv {
822 "attempted to divide by zero"
823 } else {
824 "attempted remainder with a divisor of zero"
825 };
826 let is_zero = match ty::get(rhs_t).sty {
827 ty::ty_int(t) => {
828 let zero = C_integral(Type::int_from_ty(cx.ccx(), t), 0u64, false);
829 ICmp(cx, lib::llvm::IntEQ, rhs, zero)
830 }
831 ty::ty_uint(t) => {
832 let zero = C_integral(Type::uint_from_ty(cx.ccx(), t), 0u64, false);
833 ICmp(cx, lib::llvm::IntEQ, rhs, zero)
834 }
835 _ => {
836 cx.sess().bug("fail-if-zero on unexpected type: ".to_owned() +
837 ty_to_str(cx.tcx(), rhs_t));
838 }
839 };
840 with_cond(cx, is_zero, |bcx| {
841 controlflow::trans_fail(bcx, span, InternedString::new(text))
842 })
843 }
844
845 pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
846 let name = csearch::get_symbol(&ccx.sess().cstore, did);
847 match ty::get(t).sty {
848 ty::ty_bare_fn(ref fn_ty) => {
849 match fn_ty.abi.for_target(ccx.sess().targ_cfg.os,
850 ccx.sess().targ_cfg.arch) {
851 Some(Rust) | Some(RustIntrinsic) => {
852 get_extern_rust_fn(ccx,
853 fn_ty.sig.inputs.as_slice(),
854 fn_ty.sig.output,
855 name,
856 did)
857 }
858 Some(..) | None => {
859 let c = foreign::llvm_calling_convention(ccx, fn_ty.abi);
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,
863 name, cconv, llty, fn_ty.sig.output)
864 }
865 }
866 }
867 ty::ty_closure(ref f) => {
868 get_extern_rust_fn(ccx,
869 f.sig.inputs.as_slice(),
870 f.sig.output,
871 name,
872 did)
873 }
874 _ => {
875 let llty = type_of(ccx, t);
876 get_extern_const(&mut *ccx.externs.borrow_mut(), ccx.llmod, name,
877 llty)
878 }
879 }
880 }
881
882 pub fn invoke<'a>(
883 bcx: &'a Block<'a>,
884 llfn: ValueRef,
885 llargs: Vec<ValueRef> ,
886 attributes: &[(uint, lib::llvm::Attribute)],
887 call_info: Option<NodeInfo>)
888 -> (ValueRef, &'a Block<'a>) {
889 let _icx = push_ctxt("invoke_");
890 if bcx.unreachable.get() {
891 return (C_null(Type::i8(bcx.ccx())), bcx);
892 }
893
894 match bcx.opt_node_id {
895 None => {
896 debug!("invoke at ???");
897 }
898 Some(id) => {
899 debug!("invoke at {}", bcx.tcx().map.node_to_str(id));
900 }
901 }
902
903 if need_invoke(bcx) {
904 debug!("invoking {} at {}", llfn, bcx.llbb);
905 for &llarg in llargs.iter() {
906 debug!("arg: {}", llarg);
907 }
908 let normal_bcx = bcx.fcx.new_temp_block("normal-return");
909 let landing_pad = bcx.fcx.get_landing_pad();
910
911 match call_info {
912 Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
913 None => debuginfo::clear_source_location(bcx.fcx)
914 };
915
916 let llresult = Invoke(bcx,
917 llfn,
918 llargs.as_slice(),
919 normal_bcx.llbb,
920 landing_pad,
921 attributes);
922 return (llresult, normal_bcx);
923 } else {
924 debug!("calling {} at {}", llfn, bcx.llbb);
925 for &llarg in llargs.iter() {
926 debug!("arg: {}", llarg);
927 }
928
929 match call_info {
930 Some(info) => debuginfo::set_source_location(bcx.fcx, info.id, info.span),
931 None => debuginfo::clear_source_location(bcx.fcx)
932 };
933
934 let llresult = Call(bcx, llfn, llargs.as_slice(), attributes);
935 return (llresult, bcx);
936 }
937 }
938
939 pub fn need_invoke(bcx: &Block) -> bool {
940 if bcx.sess().no_landing_pads() {
941 return false;
942 }
943
944 // Avoid using invoke if we are already inside a landing pad.
945 if bcx.is_lpad {
946 return false;
947 }
948
949 bcx.fcx.needs_invoke()
950 }
951
952 pub fn load_if_immediate(cx: &Block, v: ValueRef, t: ty::t) -> ValueRef {
953 let _icx = push_ctxt("load_if_immediate");
954 if type_is_immediate(cx.ccx(), t) { return Load(cx, v); }
955 return v;
956 }
957
958 pub fn ignore_lhs(_bcx: &Block, local: &ast::Local) -> bool {
959 match local.pat.node {
960 ast::PatWild => true, _ => false
961 }
962 }
963
964 pub fn init_local<'a>(bcx: &'a Block<'a>, local: &ast::Local)
965 -> &'a Block<'a> {
966
967 debug!("init_local(bcx={}, local.id={:?})",
968 bcx.to_str(), local.id);
969 let _indenter = indenter();
970
971 let _icx = push_ctxt("init_local");
972
973 if ignore_lhs(bcx, local) {
974 // Handle let _ = e; just like e;
975 match local.init {
976 Some(init) => {
977 return controlflow::trans_stmt_semi(bcx, init)
978 }
979 None => { return bcx; }
980 }
981 }
982
983 _match::store_local(bcx, local)
984 }
985
986 pub fn raw_block<'a>(
987 fcx: &'a FunctionContext<'a>,
988 is_lpad: bool,
989 llbb: BasicBlockRef)
990 -> &'a Block<'a> {
991 Block::new(llbb, is_lpad, None, fcx)
992 }
993
994 pub fn with_cond<'a>(
995 bcx: &'a Block<'a>,
996 val: ValueRef,
997 f: |&'a Block<'a>| -> &'a Block<'a>)
998 -> &'a Block<'a> {
999 let _icx = push_ctxt("with_cond");
1000 let fcx = bcx.fcx;
1001 let next_cx = fcx.new_temp_block("next");
1002 let cond_cx = fcx.new_temp_block("cond");
1003 CondBr(bcx, val, cond_cx.llbb, next_cx.llbb);
1004 let after_cx = f(cond_cx);
1005 if !after_cx.terminated.get() {
1006 Br(after_cx, next_cx.llbb);
1007 }
1008 next_cx
1009 }
1010
1011 pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
1012 let _icx = push_ctxt("call_memcpy");
1013 let ccx = cx.ccx();
1014 let key = match ccx.sess().targ_cfg.arch {
1015 X86 | Arm | Mips => "llvm.memcpy.p0i8.p0i8.i32",
1016 X86_64 => "llvm.memcpy.p0i8.p0i8.i64"
1017 };
1018 let memcpy = ccx.get_intrinsic(&key);
1019 let src_ptr = PointerCast(cx, src, Type::i8p(ccx));
1020 let dst_ptr = PointerCast(cx, dst, Type::i8p(ccx));
1021 let size = IntCast(cx, n_bytes, ccx.int_type);
1022 let align = C_i32(ccx, align as i32);
1023 let volatile = C_i1(ccx, false);
1024 Call(cx, memcpy, [dst_ptr, src_ptr, size, align, volatile], []);
1025 }
1026
1027 pub fn memcpy_ty(bcx: &Block, dst: ValueRef, src: ValueRef, t: ty::t) {
1028 let _icx = push_ctxt("memcpy_ty");
1029 let ccx = bcx.ccx();
1030 if ty::type_is_structural(t) {
1031 let llty = type_of::type_of(ccx, t);
1032 let llsz = llsize_of(ccx, llty);
1033 let llalign = llalign_of_min(ccx, llty);
1034 call_memcpy(bcx, dst, src, llsz, llalign as u32);
1035 } else {
1036 Store(bcx, Load(bcx, src), dst);
1037 }
1038 }
1039
1040 pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) {
1041 if cx.unreachable.get() { return; }
1042 let _icx = push_ctxt("zero_mem");
1043 let bcx = cx;
1044 let ccx = cx.ccx();
1045 let llty = type_of::type_of(ccx, t);
1046 memzero(&B(bcx), llptr, llty);
1047 }
1048
1049 // Always use this function instead of storing a zero constant to the memory
1050 // in question. If you store a zero constant, LLVM will drown in vreg
1051 // allocation for large data structures, and the generated code will be
1052 // awful. (A telltale sign of this is large quantities of
1053 // `mov [byte ptr foo],0` in the generated code.)
1054 fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
1055 let _icx = push_ctxt("memzero");
1056 let ccx = b.ccx;
1057
1058 let intrinsic_key = match ccx.sess().targ_cfg.arch {
1059 X86 | Arm | Mips => "llvm.memset.p0i8.i32",
1060 X86_64 => "llvm.memset.p0i8.i64"
1061 };
1062
1063 let llintrinsicfn = ccx.get_intrinsic(&intrinsic_key);
1064 let llptr = b.pointercast(llptr, Type::i8(ccx).ptr_to());
1065 let llzeroval = C_u8(ccx, 0);
1066 let size = machine::llsize_of(ccx, ty);
1067 let align = C_i32(ccx, llalign_of_min(ccx, ty) as i32);
1068 let volatile = C_i1(ccx, false);
1069 b.call(llintrinsicfn, [llptr, llzeroval, size, align, volatile], []);
1070 }
1071
1072 pub fn alloc_ty(bcx: &Block, t: ty::t, name: &str) -> ValueRef {
1073 let _icx = push_ctxt("alloc_ty");
1074 let ccx = bcx.ccx();
1075 let ty = type_of::type_of(ccx, t);
1076 assert!(!ty::type_has_params(t));
1077 let val = alloca(bcx, ty, name);
1078 return val;
1079 }
1080
1081 pub fn alloca(cx: &Block, ty: Type, name: &str) -> ValueRef {
1082 alloca_maybe_zeroed(cx, ty, name, false)
1083 }
1084
1085 pub fn alloca_maybe_zeroed(cx: &Block, ty: Type, name: &str, zero: bool) -> ValueRef {
1086 let _icx = push_ctxt("alloca");
1087 if cx.unreachable.get() {
1088 unsafe {
1089 return llvm::LLVMGetUndef(ty.ptr_to().to_ref());
1090 }
1091 }
1092 debuginfo::clear_source_location(cx.fcx);
1093 let p = Alloca(cx, ty, name);
1094 if zero {
1095 let b = cx.fcx.ccx.builder();
1096 b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
1097 memzero(&b, p, ty);
1098 }
1099 p
1100 }
1101
1102 pub fn arrayalloca(cx: &Block, ty: Type, v: ValueRef) -> ValueRef {
1103 let _icx = push_ctxt("arrayalloca");
1104 if cx.unreachable.get() {
1105 unsafe {
1106 return llvm::LLVMGetUndef(ty.to_ref());
1107 }
1108 }
1109 debuginfo::clear_source_location(cx.fcx);
1110 return ArrayAlloca(cx, ty, v);
1111 }
1112
1113 // Creates and returns space for, or returns the argument representing, the
1114 // slot where the return value of the function must go.
1115 pub fn make_return_pointer(fcx: &FunctionContext, output_type: ty::t)
1116 -> ValueRef {
1117 unsafe {
1118 if type_of::return_uses_outptr(fcx.ccx, output_type) {
1119 llvm::LLVMGetParam(fcx.llfn, 0)
1120 } else {
1121 let lloutputtype = type_of::type_of(fcx.ccx, output_type);
1122 let bcx = fcx.entry_bcx.borrow().clone().unwrap();
1123 Alloca(bcx, lloutputtype, "__make_return_pointer")
1124 }
1125 }
1126 }
1127
1128 // NB: must keep 4 fns in sync:
1129 //
1130 // - type_of_fn
1131 // - create_datums_for_fn_args.
1132 // - new_fn_ctxt
1133 // - trans_args
1134 //
1135 // Be warned! You must call `init_function` before doing anything with the
1136 // returned function context.
1137 pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
1138 llfndecl: ValueRef,
1139 id: ast::NodeId,
1140 has_env: bool,
1141 output_type: ty::t,
1142 param_substs: Option<&'a param_substs>,
1143 sp: Option<Span>,
1144 block_arena: &'a TypedArena<Block<'a>>)
1145 -> FunctionContext<'a> {
1146 for p in param_substs.iter() { p.validate(); }
1147
1148 debug!("new_fn_ctxt(path={}, id={}, param_substs={})",
1149 if id == -1 {
1150 "".to_owned()
1151 } else {
1152 ccx.tcx.map.path_to_str(id).to_owned()
1153 },
1154 id, param_substs.map(|s| s.repr(ccx.tcx())));
1155
1156 let substd_output_type = match param_substs {
1157 None => output_type,
1158 Some(substs) => {
1159 ty::subst_tps(ccx.tcx(),
1160 substs.tys.as_slice(),
1161 substs.self_ty,
1162 output_type)
1163 }
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);
1167
1168 let mut fcx = FunctionContext {
1169 llfn: llfndecl,
1170 llenv: None,
1171 llretptr: Cell::new(None),
1172 entry_bcx: RefCell::new(None),
1173 alloca_insert_pt: Cell::new(None),
1174 llreturn: Cell::new(None),
1175 personality: Cell::new(None),
1176 caller_expects_out_pointer: uses_outptr,
1177 llargs: RefCell::new(NodeMap::new()),
1178 lllocals: RefCell::new(NodeMap::new()),
1179 llupvars: RefCell::new(NodeMap::new()),
1180 id: id,
1181 param_substs: param_substs,
1182 span: sp,
1183 block_arena: block_arena,
1184 ccx: ccx,
1185 debug_context: debug_context,
1186 scopes: RefCell::new(Vec::new())
1187 };
1188
1189 if has_env {
1190 fcx.llenv = Some(unsafe {
1191 llvm::LLVMGetParam(fcx.llfn, fcx.env_arg_pos() as c_uint)
1192 });
1193 }
1194
1195 fcx
1196 }
1197
1198 /// Performs setup on a newly created function, creating the entry scope block
1199 /// and allocating space for the return pointer.
1200 pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
1201 skip_retptr: bool,
1202 output_type: ty::t) {
1203 let entry_bcx = fcx.new_temp_block("entry-block");
1204
1205 *fcx.entry_bcx.borrow_mut() = Some(entry_bcx);
1206
1207 // Use a dummy instruction as the insertion point for all allocas.
1208 // This is later removed in FunctionContext::cleanup.
1209 fcx.alloca_insert_pt.set(Some(unsafe {
1210 Load(entry_bcx, C_null(Type::i8p(fcx.ccx)));
1211 llvm::LLVMGetFirstInstruction(entry_bcx.llbb)
1212 }));
1213
1214 // This shouldn't need to recompute the return type,
1215 // as new_fn_ctxt did it already.
1216 let substd_output_type = match fcx.param_substs {
1217 None => output_type,
1218 Some(substs) => {
1219 ty::subst_tps(fcx.ccx.tcx(),
1220 substs.tys.as_slice(),
1221 substs.self_ty,
1222 output_type)
1223 }
1224 };
1225
1226 if !return_type_is_void(fcx.ccx, substd_output_type) {
1227 // If the function returns nil/bot, there is no real return
1228 // value, so do not set `llretptr`.
1229 if !skip_retptr || fcx.caller_expects_out_pointer {
1230 // Otherwise, we normally allocate the llretptr, unless we
1231 // have been instructed to skip it for immediate return
1232 // values.
1233 fcx.llretptr.set(Some(make_return_pointer(fcx, substd_output_type)));
1234 }
1235 }
1236 }
1237
1238 // NB: must keep 4 fns in sync:
1239 //
1240 // - type_of_fn
1241 // - create_datums_for_fn_args.
1242 // - new_fn_ctxt
1243 // - trans_args
1244
1245 fn arg_kind(cx: &FunctionContext, t: ty::t) -> datum::Rvalue {
1246 use middle::trans::datum::{ByRef, ByValue};
1247
1248 datum::Rvalue {
1249 mode: if arg_is_indirect(cx.ccx, t) { ByRef } else { ByValue }
1250 }
1251 }
1252
1253 // work around bizarre resolve errors
1254 pub type RvalueDatum = datum::Datum<datum::Rvalue>;
1255 pub type LvalueDatum = datum::Datum<datum::Lvalue>;
1256
1257 // create_datums_for_fn_args: creates rvalue datums for each of the
1258 // incoming function arguments. These will later be stored into
1259 // appropriate lvalue datums.
1260 pub fn create_datums_for_fn_args(fcx: &FunctionContext,
1261 arg_tys: &[ty::t])
1262 -> Vec<RvalueDatum> {
1263 let _icx = push_ctxt("create_datums_for_fn_args");
1264
1265 // Return an array wrapping the ValueRefs that we get from
1266 // llvm::LLVMGetParam for each argument into datums.
1267 arg_tys.iter().enumerate().map(|(i, &arg_ty)| {
1268 let llarg = unsafe {
1269 llvm::LLVMGetParam(fcx.llfn, fcx.arg_pos(i) as c_uint)
1270 };
1271 datum::Datum(llarg, arg_ty, arg_kind(fcx, arg_ty))
1272 }).collect()
1273 }
1274
1275 fn copy_args_to_allocas<'a>(fcx: &FunctionContext<'a>,
1276 arg_scope: cleanup::CustomScopeIndex,
1277 bcx: &'a Block<'a>,
1278 args: &[ast::Arg],
1279 arg_datums: Vec<RvalueDatum> )
1280 -> &'a Block<'a> {
1281 debug!("copy_args_to_allocas");
1282
1283 let _icx = push_ctxt("copy_args_to_allocas");
1284 let mut bcx = bcx;
1285
1286 let arg_scope_id = cleanup::CustomScope(arg_scope);
1287
1288 for (i, arg_datum) in arg_datums.move_iter().enumerate() {
1289 // For certain mode/type combinations, the raw llarg values are passed
1290 // by value. However, within the fn body itself, we want to always
1291 // have all locals and arguments be by-ref so that we can cancel the
1292 // cleanup and for better interaction with LLVM's debug info. So, if
1293 // the argument would be passed by value, we store it into an alloca.
1294 // This alloca should be optimized away by LLVM's mem-to-reg pass in
1295 // the event it's not truly needed.
1296
1297 bcx = _match::store_arg(bcx, args[i].pat, arg_datum, arg_scope_id);
1298
1299 if fcx.ccx.sess().opts.debuginfo == FullDebugInfo {
1300 debuginfo::create_argument_metadata(bcx, &args[i]);
1301 }
1302 }
1303
1304 bcx
1305 }
1306
1307 // Ties up the llstaticallocas -> llloadenv -> lltop edges,
1308 // and builds the return block.
1309 pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
1310 last_bcx: &'a Block<'a>) {
1311 let _icx = push_ctxt("finish_fn");
1312
1313 let ret_cx = match fcx.llreturn.get() {
1314 Some(llreturn) => {
1315 if !last_bcx.terminated.get() {
1316 Br(last_bcx, llreturn);
1317 }
1318 raw_block(fcx, false, llreturn)
1319 }
1320 None => last_bcx
1321 };
1322 build_return_block(fcx, ret_cx);
1323 debuginfo::clear_source_location(fcx);
1324 fcx.cleanup();
1325 }
1326
1327 // Builds the return block for a function.
1328 pub fn build_return_block(fcx: &FunctionContext, ret_cx: &Block) {
1329 // Return the value if this function immediate; otherwise, return void.
1330 if fcx.llretptr.get().is_none() || fcx.caller_expects_out_pointer {
1331 return RetVoid(ret_cx);
1332 }
1333
1334 let retptr = Value(fcx.llretptr.get().unwrap());
1335 let retval = match retptr.get_dominating_store(ret_cx) {
1336 // If there's only a single store to the ret slot, we can directly return
1337 // the value that was stored and omit the store and the alloca
1338 Some(s) => {
1339 let retval = s.get_operand(0).unwrap().get();
1340 s.erase_from_parent();
1341
1342 if retptr.has_no_uses() {
1343 retptr.erase_from_parent();
1344 }
1345
1346 retval
1347 }
1348 // Otherwise, load the return value from the ret slot
1349 None => Load(ret_cx, fcx.llretptr.get().unwrap())
1350 };
1351
1352
1353 Ret(ret_cx, retval);
1354 }
1355
1356 // trans_closure: Builds an LLVM function out of a source function.
1357 // If the function closes over its environment a closure will be
1358 // returned.
1359 pub fn trans_closure(ccx: &CrateContext,
1360 decl: &ast::FnDecl,
1361 body: &ast::Block,
1362 llfndecl: ValueRef,
1363 param_substs: Option<¶m_substs>,
1364 id: ast::NodeId,
1365 _attributes: &[ast::Attribute],
1366 output_type: ty::t,
1367 maybe_load_env: <'a> |&'a Block<'a>| -> &'a Block<'a>) {
1368 ccx.stats.n_closures.set(ccx.stats.n_closures.get() + 1);
1369
1370 let _icx = push_ctxt("trans_closure");
1371 set_uwtable(llfndecl);
1372
1373 debug!("trans_closure(..., param_substs={})",
1374 param_substs.map(|s| s.repr(ccx.tcx())));
1375
1376 let has_env = match ty::get(ty::node_id_to_type(ccx.tcx(), id)).sty {
1377 ty::ty_closure(_) => true,
1378 _ => false
1379 };
1380
1381 let arena = TypedArena::new();
1382 let fcx = new_fn_ctxt(ccx,
1383 llfndecl,
1384 id,
1385 has_env,
1386 output_type,
1387 param_substs.map(|s| &*s),
1388 Some(body.span),
1389 &arena);
1390 init_function(&fcx, false, output_type);
1391
1392 // cleanup scope for the incoming arguments
1393 let arg_scope = fcx.push_custom_cleanup_scope();
1394
1395 // Create the first basic block in the function and keep a handle on it to
1396 // pass to finish_fn later.
1397 let bcx_top = fcx.entry_bcx.borrow().clone().unwrap();
1398 let mut bcx = bcx_top;
1399 let block_ty = node_id_type(bcx, body.id);
1400
1401 // Set up arguments to the function.
1402 let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
1403 let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
1404
1405 bcx = copy_args_to_allocas(&fcx,
1406 arg_scope,
1407 bcx,
1408 decl.inputs.as_slice(),
1409 arg_datums);
1410
1411 bcx = maybe_load_env(bcx);
1412
1413 // Up until here, IR instructions for this function have explicitly not been annotated with
1414 // source code location, so we don't step into call setup code. From here on, source location
1415 // emitting should be enabled.
1416 debuginfo::start_emitting_source_locations(&fcx);
1417
1418 let dest = match fcx.llretptr.get() {
1419 Some(e) => {expr::SaveIn(e)}
1420 None => {
1421 assert!(type_is_zero_size(bcx.ccx(), block_ty))
1422 expr::Ignore
1423 }
1424 };
1425
1426 // This call to trans_block is the place where we bridge between
1427 // translation calls that don't have a return value (trans_crate,
1428 // trans_mod, trans_item, et cetera) and those that do
1429 // (trans_block, trans_expr, et cetera).
1430 bcx = controlflow::trans_block(bcx, body, dest);
1431
1432 match fcx.llreturn.get() {
1433 Some(_) => {
1434 Br(bcx, fcx.return_exit_block());
1435 fcx.pop_custom_cleanup_scope(arg_scope);
1436 }
1437 None => {
1438 // Microoptimization writ large: avoid creating a separate
1439 // llreturn basic block
1440 bcx = fcx.pop_and_trans_custom_cleanup_scope(bcx, arg_scope);
1441 }
1442 };
1443
1444 // Put return block after all other blocks.
1445 // This somewhat improves single-stepping experience in debugger.
1446 unsafe {
1447 let llreturn = fcx.llreturn.get();
1448 for &llreturn in llreturn.iter() {
1449 llvm::LLVMMoveBasicBlockAfter(llreturn, bcx.llbb);
1450 }
1451 }
1452
1453 // Insert the mandatory first few basic blocks before lltop.
1454 finish_fn(&fcx, bcx);
1455 }
1456
1457 // trans_fn: creates an LLVM function corresponding to a source language
1458 // function.
1459 pub fn trans_fn(ccx: &CrateContext,
1460 decl: &ast::FnDecl,
1461 body: &ast::Block,
1462 llfndecl: ValueRef,
1463 param_substs: Option<¶m_substs>,
1464 id: ast::NodeId,
1465 attrs: &[ast::Attribute]) {
1466 let _s = StatRecorder::new(ccx, ccx.tcx.map.path_to_str(id).to_owned());
1467 debug!("trans_fn(param_substs={})", param_substs.map(|s| s.repr(ccx.tcx())));
1468 let _icx = push_ctxt("trans_fn");
1469 let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id));
1470 trans_closure(ccx, decl, body, llfndecl,
1471 param_substs, id, attrs, output_type, |bcx| bcx);
1472 }
1473
1474 pub fn trans_enum_variant(ccx: &CrateContext,
1475 _enum_id: ast::NodeId,
1476 variant: &ast::Variant,
1477 _args: &[ast::VariantArg],
1478 disr: ty::Disr,
1479 param_substs: Option<¶m_substs>,
1480 llfndecl: ValueRef) {
1481 let _icx = push_ctxt("trans_enum_variant");
1482
1483 trans_enum_variant_or_tuple_like_struct(
1484 ccx,
1485 variant.node.id,
1486 disr,
1487 param_substs,
1488 llfndecl);
1489 }
1490
1491 pub fn trans_tuple_struct(ccx: &CrateContext,
1492 _fields: &[ast::StructField],
1493 ctor_id: ast::NodeId,
1494 param_substs: Option<¶m_substs>,
1495 llfndecl: ValueRef) {
1496 let _icx = push_ctxt("trans_tuple_struct");
1497
1498 trans_enum_variant_or_tuple_like_struct(
1499 ccx,
1500 ctor_id,
1501 0,
1502 param_substs,
1503 llfndecl);
1504 }
1505
1506 fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
1507 ctor_id: ast::NodeId,
1508 disr: ty::Disr,
1509 param_substs: Option<¶m_substs>,
1510 llfndecl: ValueRef) {
1511 let ctor_ty = {
1512 let no_substs: &[ty::t] = [];
1513 let ty_param_substs: &[ty::t] = match param_substs {
1514 Some(substs) => substs.tys.as_slice(),
1515 None => no_substs
1516 };
1517
1518 ty::subst_tps(ccx.tcx(),
1519 ty_param_substs,
1520 None,
1521 ty::node_id_to_type(ccx.tcx(), ctor_id))
1522 };
1523
1524 let result_ty = match ty::get(ctor_ty).sty {
1525 ty::ty_bare_fn(ref bft) => bft.sig.output,
1526 _ => ccx.sess().bug(
1527 format!("trans_enum_variant_or_tuple_like_struct: \
1528 unexpected ctor return type {}",
1529 ty_to_str(ccx.tcx(), ctor_ty)))
1530 };
1531
1532 let arena = TypedArena::new();
1533 let fcx = new_fn_ctxt(ccx, llfndecl, ctor_id, false, result_ty,
1534 param_substs.map(|s| &*s), None, &arena);
1535 init_function(&fcx, false, result_ty);
1536
1537 let arg_tys = ty::ty_fn_args(ctor_ty);
1538
1539 let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
1540
1541 let bcx = fcx.entry_bcx.borrow().clone().unwrap();
1542
1543 if !type_is_zero_size(fcx.ccx, result_ty) {
1544 let repr = adt::represent_type(ccx, result_ty);
1545 adt::trans_start_init(bcx, &*repr, fcx.llretptr.get().unwrap(), disr);
1546 for (i, arg_datum) in arg_datums.move_iter().enumerate() {
1547 let lldestptr = adt::trans_field_ptr(bcx,
1548 &*repr,
1549 fcx.llretptr.get().unwrap(),
1550 disr,
1551 i);
1552 arg_datum.store_to(bcx, lldestptr);
1553 }
1554 }
1555
1556 finish_fn(&fcx, bcx);
1557 }
1558
1559 fn trans_enum_def(ccx: &CrateContext, enum_definition: &ast::EnumDef,
1560 id: ast::NodeId, vi: &[Rc<ty::VariantInfo>],
1561 i: &mut uint) {
1562 for &variant in enum_definition.variants.iter() {
1563 let disr_val = vi[*i].disr_val;
1564 *i += 1;
1565
1566 match variant.node.kind {
1567 ast::TupleVariantKind(ref args) if args.len() > 0 => {
1568 let llfn = get_item_val(ccx, variant.node.id);
1569 trans_enum_variant(ccx, id, variant, args.as_slice(),
1570 disr_val, None, llfn);
1571 }
1572 ast::TupleVariantKind(_) => {
1573 // Nothing to do.
1574 }
1575 ast::StructVariantKind(struct_def) => {
1576 trans_struct_def(ccx, struct_def);
1577 }
1578 }
1579 }
1580 }
1581
1582 pub struct TransItemVisitor<'a> {
1583 pub ccx: &'a CrateContext,
1584 }
1585
1586 impl<'a> Visitor<()> for TransItemVisitor<'a> {
1587 fn visit_item(&mut self, i: &ast::Item, _:()) {
1588 trans_item(self.ccx, i);
1589 }
1590 }
1591
1592 pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
1593 let _icx = push_ctxt("trans_item");
1594 match item.node {
1595 ast::ItemFn(decl, _fn_style, abi, ref generics, body) => {
1596 if abi != Rust {
1597 let llfndecl = get_item_val(ccx, item.id);
1598 foreign::trans_rust_fn_with_foreign_abi(
1599 ccx, decl, body, item.attrs.as_slice(), llfndecl, item.id);
1600 } else if !generics.is_type_parameterized() {
1601 let llfn = get_item_val(ccx, item.id);
1602 trans_fn(ccx,
1603 decl,
1604 body,
1605 llfn,
1606 None,
1607 item.id,
1608 item.attrs.as_slice());
1609 } else {
1610 // Be sure to travel more than just one layer deep to catch nested
1611 // items in blocks and such.
1612 let mut v = TransItemVisitor{ ccx: ccx };
1613 v.visit_block(body, ());
1614 }
1615 }
1616 ast::ItemImpl(ref generics, _, _, ref ms) => {
1617 meth::trans_impl(ccx, item.ident, ms.as_slice(), generics, item.id);
1618 }
1619 ast::ItemMod(ref m) => {
1620 trans_mod(ccx, m);
1621 }
1622 ast::ItemEnum(ref enum_definition, ref generics) => {
1623 if !generics.is_type_parameterized() {
1624 let vi = ty::enum_variants(ccx.tcx(), local_def(item.id));
1625 let mut i = 0;
1626 trans_enum_def(ccx, enum_definition, item.id, vi.as_slice(), &mut i);
1627 }
1628 }
1629 ast::ItemStatic(_, m, expr) => {
1630 consts::trans_const(ccx, m, item.id);
1631 // Do static_assert checking. It can't really be done much earlier
1632 // because we need to get the value of the bool out of LLVM
1633 if attr::contains_name(item.attrs.as_slice(), "static_assert") {
1634 if m == ast::MutMutable {
1635 ccx.sess().span_fatal(expr.span,
1636 "cannot have static_assert on a mutable \
1637 static");
1638 }
1639
1640 let v = ccx.const_values.borrow().get_copy(&item.id);
1641 unsafe {
1642 if !(llvm::LLVMConstIntGetZExtValue(v) != 0) {
1643 ccx.sess().span_fatal(expr.span, "static assertion failed");
1644 }
1645 }
1646 }
1647 },
1648 ast::ItemForeignMod(ref foreign_mod) => {
1649 foreign::trans_foreign_mod(ccx, foreign_mod);
1650 }
1651 ast::ItemStruct(struct_def, ref generics) => {
1652 if !generics.is_type_parameterized() {
1653 trans_struct_def(ccx, struct_def);
1654 }
1655 }
1656 ast::ItemTrait(..) => {
1657 // Inside of this trait definition, we won't be actually translating any
1658 // functions, but the trait still needs to be walked. Otherwise default
1659 // methods with items will not get translated and will cause ICE's when
1660 // metadata time comes around.
1661 let mut v = TransItemVisitor{ ccx: ccx };
1662 visit::walk_item(&mut v, item, ());
1663 }
1664 _ => {/* fall through */ }
1665 }
1666 }
1667
1668 pub fn trans_struct_def(ccx: &CrateContext, struct_def: @ast::StructDef) {
1669 // If this is a tuple-like struct, translate the constructor.
1670 match struct_def.ctor_id {
1671 // We only need to translate a constructor if there are fields;
1672 // otherwise this is a unit-like struct.
1673 Some(ctor_id) if struct_def.fields.len() > 0 => {
1674 let llfndecl = get_item_val(ccx, ctor_id);
1675 trans_tuple_struct(ccx, struct_def.fields.as_slice(),
1676 ctor_id, None, llfndecl);
1677 }
1678 Some(_) | None => {}
1679 }
1680 }
1681
1682 // Translate a module. Doing this amounts to translating the items in the
1683 // module; there ends up being no artifact (aside from linkage names) of
1684 // separate modules in the compiled program. That's because modules exist
1685 // only as a convenience for humans working with the code, to organize names
1686 // and control visibility.
1687 pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) {
1688 let _icx = push_ctxt("trans_mod");
1689 for item in m.items.iter() {
1690 trans_item(ccx, *item);
1691 }
1692 }
1693
1694 fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: ~str, node_id: ast::NodeId,
1695 llfn: ValueRef) {
1696 ccx.item_symbols.borrow_mut().insert(node_id, sym);
1697
1698 if !ccx.reachable.contains(&node_id) {
1699 lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
1700 }
1701
1702 if is_entry_fn(ccx.sess(), node_id) {
1703 create_entry_wrapper(ccx, sp, llfn);
1704 }
1705 }
1706
1707 fn register_fn(ccx: &CrateContext,
1708 sp: Span,
1709 sym: ~str,
1710 node_id: ast::NodeId,
1711 node_type: ty::t)
1712 -> ValueRef {
1713 let f = match ty::get(node_type).sty {
1714 ty::ty_bare_fn(ref f) => {
1715 assert!(f.abi == Rust || f.abi == RustIntrinsic);
1716 f
1717 }
1718 _ => fail!("expected bare rust fn or an intrinsic")
1719 };
1720
1721 let llfn = decl_rust_fn(ccx,
1722 false,
1723 f.sig.inputs.as_slice(),
1724 f.sig.output,
1725 sym);
1726 finish_register_fn(ccx, sp, sym, node_id, llfn);
1727 llfn
1728 }
1729
1730 // only use this for foreign function ABIs and glue, use `register_fn` for Rust functions
1731 pub fn register_fn_llvmty(ccx: &CrateContext,
1732 sp: Span,
1733 sym: ~str,
1734 node_id: ast::NodeId,
1735 cc: lib::llvm::CallConv,
1736 fn_ty: Type,
1737 output: ty::t) -> ValueRef {
1738 debug!("register_fn_llvmty id={} sym={}", node_id, sym);
1739
1740 let llfn = decl_fn(ccx.llmod, sym, cc, fn_ty, output);
1741 finish_register_fn(ccx, sp, sym, node_id, llfn);
1742 llfn
1743 }
1744
1745 pub fn is_entry_fn(sess: &Session, node_id: ast::NodeId) -> bool {
1746 match *sess.entry_fn.borrow() {
1747 Some((entry_id, _)) => node_id == entry_id,
1748 None => false
1749 }
1750 }
1751
1752 // Create a _rust_main(args: ~[str]) function which will be called from the
1753 // runtime rust_start function
1754 pub fn create_entry_wrapper(ccx: &CrateContext,
1755 _sp: Span,
1756 main_llfn: ValueRef) {
1757 let et = ccx.sess().entry_type.get().unwrap();
1758 match et {
1759 session::EntryMain => {
1760 create_entry_fn(ccx, main_llfn, true);
1761 }
1762 session::EntryStart => create_entry_fn(ccx, main_llfn, false),
1763 session::EntryNone => {} // Do nothing.
1764 }
1765
1766 fn create_entry_fn(ccx: &CrateContext,
1767 rust_main: ValueRef,
1768 use_start_lang_item: bool) {
1769 let llfty = Type::func([ccx.int_type, Type::i8p(ccx).ptr_to()],
1770 &ccx.int_type);
1771
1772 let llfn = decl_cdecl_fn(ccx.llmod, "main", llfty, ty::mk_nil());
1773 let llbb = "top".with_c_str(|buf| {
1774 unsafe {
1775 llvm::LLVMAppendBasicBlockInContext(ccx.llcx, llfn, buf)
1776 }
1777 });
1778 let bld = ccx.builder.b;
1779 unsafe {
1780 llvm::LLVMPositionBuilderAtEnd(bld, llbb);
1781
1782 let (start_fn, args) = if use_start_lang_item {
1783 let start_def_id = match ccx.tcx.lang_items.require(StartFnLangItem) {
1784 Ok(id) => id,
1785 Err(s) => { ccx.sess().fatal(s); }
1786 };
1787 let start_fn = if start_def_id.krate == ast::LOCAL_CRATE {
1788 get_item_val(ccx, start_def_id.node)
1789 } else {
1790 let start_fn_type = csearch::get_type(ccx.tcx(),
1791 start_def_id).ty;
1792 trans_external_path(ccx, start_def_id, start_fn_type)
1793 };
1794
1795 let args = {
1796 let opaque_rust_main = "rust_main".with_c_str(|buf| {
1797 llvm::LLVMBuildPointerCast(bld, rust_main, Type::i8p(ccx).to_ref(), buf)
1798 });
1799
1800 vec!(
1801 opaque_rust_main,
1802 llvm::LLVMGetParam(llfn, 0),
1803 llvm::LLVMGetParam(llfn, 1)
1804 )
1805 };
1806 (start_fn, args)
1807 } else {
1808 debug!("using user-defined start fn");
1809 let args = vec!(
1810 llvm::LLVMGetParam(llfn, 0 as c_uint),
1811 llvm::LLVMGetParam(llfn, 1 as c_uint)
1812 );
1813
1814 (rust_main, args)
1815 };
1816
1817 let result = llvm::LLVMBuildCall(bld,
1818 start_fn,
1819 args.as_ptr(),
1820 args.len() as c_uint,
1821 noname());
1822
1823 llvm::LLVMBuildRet(bld, result);
1824 }
1825 }
1826 }
1827
1828 fn exported_name(ccx: &CrateContext, id: ast::NodeId,
1829 ty: ty::t, attrs: &[ast::Attribute]) -> ~str {
1830 match attr::first_attr_value_str_by_name(attrs, "export_name") {
1831 // Use provided name
1832 Some(name) => name.get().to_owned(),
1833
1834 _ => ccx.tcx.map.with_path(id, |mut path| {
1835 if attr::contains_name(attrs, "no_mangle") {
1836 // Don't mangle
1837 path.last().unwrap().to_str()
1838 } else {
1839 // Usual name mangling
1840 mangle_exported_name(ccx, path, ty, id)
1841 }
1842 })
1843 }
1844 }
1845
1846 pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
1847 debug!("get_item_val(id=`{:?}`)", id);
1848
1849 match ccx.item_vals.borrow().find_copy(&id) {
1850 Some(v) => return v,
1851 None => {}
1852 }
1853
1854 let mut foreign = false;
1855 let item = ccx.tcx.map.get(id);
1856 let val = match item {
1857 ast_map::NodeItem(i) => {
1858 let ty = ty::node_id_to_type(ccx.tcx(), i.id);
1859 let sym = exported_name(ccx, id, ty, i.attrs.as_slice());
1860
1861 let v = match i.node {
1862 ast::ItemStatic(_, _, expr) => {
1863 // If this static came from an external crate, then
1864 // we need to get the symbol from csearch instead of
1865 // using the current crate's name/version
1866 // information in the hash of the symbol
1867 debug!("making {}", sym);
1868 let (sym, is_local) = {
1869 match ccx.external_srcs.borrow().find(&i.id) {
1870 Some(&did) => {
1871 debug!("but found in other crate...");
1872 (csearch::get_symbol(&ccx.sess().cstore,
1873 did), false)
1874 }
1875 None => (sym, true)
1876 }
1877 };
1878
1879 // We need the translated value here, because for enums the
1880 // LLVM type is not fully determined by the Rust type.
1881 let (v, inlineable) = consts::const_expr(ccx, expr, is_local);
1882 ccx.const_values.borrow_mut().insert(id, v);
1883 let mut inlineable = inlineable;
1884
1885 unsafe {
1886 let llty = llvm::LLVMTypeOf(v);
1887 let g = sym.with_c_str(|buf| {
1888 llvm::LLVMAddGlobal(ccx.llmod, llty, buf)
1889 });
1890
1891 if !ccx.reachable.contains(&id) {
1892 lib::llvm::SetLinkage(g, lib::llvm::InternalLinkage);
1893 }
1894
1895 // Apply the `unnamed_addr` attribute if
1896 // requested
1897 if attr::contains_name(i.attrs.as_slice(),
1898 "address_insignificant") {
1899 if ccx.reachable.contains(&id) {
1900 ccx.sess().span_bug(i.span,
1901 "insignificant static is reachable");
1902 }
1903 lib::llvm::SetUnnamedAddr(g, true);
1904
1905 // This is a curious case where we must make
1906 // all of these statics inlineable. If a
1907 // global is tagged as
1908 // address_insignificant, then LLVM won't
1909 // coalesce globals unless they have an
1910 // internal linkage type. This means that
1911 // external crates cannot use this global.
1912 // This is a problem for things like inner
1913 // statics in generic functions, because the
1914 // function will be inlined into another
1915 // crate and then attempt to link to the
1916 // static in the original crate, only to
1917 // find that it's not there. On the other
1918 // side of inlininig, the crates knows to
1919 // not declare this static as
1920 // available_externally (because it isn't)
1921 inlineable = true;
1922 }
1923
1924 if attr::contains_name(i.attrs.as_slice(),
1925 "thread_local") {
1926 lib::llvm::set_thread_local(g, true);
1927 }
1928
1929 if !inlineable {
1930 debug!("{} not inlined", sym);
1931 ccx.non_inlineable_statics.borrow_mut()
1932 .insert(id);
1933 }
1934
1935 ccx.item_symbols.borrow_mut().insert(i.id, sym);
1936 g
1937 }
1938 }
1939
1940 ast::ItemFn(_, _, abi, _, _) => {
1941 let llfn = if abi == Rust {
1942 register_fn(ccx, i.span, sym, i.id, ty)
1943 } else {
1944 foreign::register_rust_fn_with_foreign_abi(ccx,
1945 i.span,
1946 sym,
1947 i.id)
1948 };
1949 set_llvm_fn_attrs(i.attrs.as_slice(), llfn);
1950 llfn
1951 }
1952
1953 _ => fail!("get_item_val: weird result in table")
1954 };
1955
1956 match attr::first_attr_value_str_by_name(i.attrs.as_slice(),
1957 "link_section") {
1958 Some(sect) => unsafe {
1959 sect.get().with_c_str(|buf| {
1960 llvm::LLVMSetSection(v, buf);
1961 })
1962 },
1963 None => ()
1964 }
1965
1966 v
1967 }
1968
1969 ast_map::NodeTraitMethod(trait_method) => {
1970 debug!("get_item_val(): processing a NodeTraitMethod");
1971 match *trait_method {
1972 ast::Required(_) => {
1973 ccx.sess().bug("unexpected variant: required trait method in \
1974 get_item_val()");
1975 }
1976 ast::Provided(m) => {
1977 register_method(ccx, id, m)
1978 }
1979 }
1980 }
1981
1982 ast_map::NodeMethod(m) => {
1983 register_method(ccx, id, m)
1984 }
1985
1986 ast_map::NodeForeignItem(ni) => {
1987 foreign = true;
1988
1989 match ni.node {
1990 ast::ForeignItemFn(..) => {
1991 let abi = ccx.tcx.map.get_foreign_abi(id);
1992 foreign::register_foreign_item_fn(ccx, abi, ni)
1993 }
1994 ast::ForeignItemStatic(..) => {
1995 foreign::register_static(ccx, ni)
1996 }
1997 }
1998 }
1999
2000 ast_map::NodeVariant(ref v) => {
2001 let llfn;
2002 let args = match v.node.kind {
2003 ast::TupleVariantKind(ref args) => args,
2004 ast::StructVariantKind(_) => {
2005 fail!("struct variant kind unexpected in get_item_val")
2006 }
2007 };
2008 assert!(args.len() != 0u);
2009 let ty = ty::node_id_to_type(ccx.tcx(), id);
2010 let parent = ccx.tcx.map.get_parent(id);
2011 let enm = ccx.tcx.map.expect_item(parent);
2012 let sym = exported_name(ccx,
2013 id,
2014 ty,
2015 enm.attrs.as_slice());
2016
2017 llfn = match enm.node {
2018 ast::ItemEnum(_, _) => {
2019 register_fn(ccx, (*v).span, sym, id, ty)
2020 }
2021 _ => fail!("NodeVariant, shouldn't happen")
2022 };
2023 set_inline_hint(llfn);
2024 llfn
2025 }
2026
2027 ast_map::NodeStructCtor(struct_def) => {
2028 // Only register the constructor if this is a tuple-like struct.
2029 let ctor_id = match struct_def.ctor_id {
2030 None => {
2031 ccx.sess().bug("attempt to register a constructor of \
2032 a non-tuple-like struct")
2033 }
2034 Some(ctor_id) => ctor_id,
2035 };
2036 let parent = ccx.tcx.map.get_parent(id);
2037 let struct_item = ccx.tcx.map.expect_item(parent);
2038 let ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
2039 let sym = exported_name(ccx,
2040 id,
2041 ty,
2042 struct_item.attrs
2043 .as_slice());
2044 let llfn = register_fn(ccx, struct_item.span,
2045 sym, ctor_id, ty);
2046 set_inline_hint(llfn);
2047 llfn
2048 }
2049
2050 ref variant => {
2051 ccx.sess().bug(format!("get_item_val(): unexpected variant: {:?}",
2052 variant))
2053 }
2054 };
2055
2056 // foreign items (extern fns and extern statics) don't have internal
2057 // linkage b/c that doesn't quite make sense. Otherwise items can
2058 // have internal linkage if they're not reachable.
2059 if !foreign && !ccx.reachable.contains(&id) {
2060 lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage);
2061 }
2062
2063 ccx.item_vals.borrow_mut().insert(id, val);
2064 val
2065 }
2066
2067 fn register_method(ccx: &CrateContext, id: ast::NodeId,
2068 m: &ast::Method) -> ValueRef {
2069 let mty = ty::node_id_to_type(ccx.tcx(), id);
2070
2071 let sym = exported_name(ccx, id, mty, m.attrs.as_slice());
2072
2073 let llfn = register_fn(ccx, m.span, sym, id, mty);
2074 set_llvm_fn_attrs(m.attrs.as_slice(), llfn);
2075 llfn
2076 }
2077
2078 pub fn p2i(ccx: &CrateContext, v: ValueRef) -> ValueRef {
2079 unsafe {
2080 return llvm::LLVMConstPtrToInt(v, ccx.int_type.to_ref());
2081 }
2082 }
2083
2084 pub fn crate_ctxt_to_encode_parms<'r>(cx: &'r CrateContext, ie: encoder::EncodeInlinedItem<'r>)
2085 -> encoder::EncodeParams<'r> {
2086 encoder::EncodeParams {
2087 diag: cx.sess().diagnostic(),
2088 tcx: cx.tcx(),
2089 reexports2: &cx.exp_map2,
2090 item_symbols: &cx.item_symbols,
2091 non_inlineable_statics: &cx.non_inlineable_statics,
2092 link_meta: &cx.link_meta,
2093 cstore: &cx.sess().cstore,
2094 encode_inlined_item: ie,
2095 }
2096 }
2097
2098 pub fn write_metadata(cx: &CrateContext, krate: &ast::Crate) -> Vec<u8> {
2099 use flate;
2100
2101 let any_library = cx.sess().crate_types.borrow().iter().any(|ty| {
2102 *ty != session::CrateTypeExecutable
2103 });
2104 if !any_library {
2105 return Vec::new()
2106 }
2107
2108 let encode_inlined_item: encoder::EncodeInlinedItem =
2109 |ecx, ebml_w, ii| astencode::encode_inlined_item(ecx, ebml_w, ii);
2110
2111 let encode_parms = crate_ctxt_to_encode_parms(cx, encode_inlined_item);
2112 let metadata = encoder::encode_metadata(encode_parms, krate);
2113 let compressed = Vec::from_slice(encoder::metadata_encoding_version)
2114 .append(match flate::deflate_bytes(metadata.as_slice()) {
2115 Some(compressed) => compressed,
2116 None => cx.sess().fatal(format!("failed to compress metadata"))
2117 }.as_slice());
2118 let llmeta = C_bytes(cx, compressed.as_slice());
2119 let llconst = C_struct(cx, [llmeta], false);
2120 let name = format!("rust_metadata_{}_{}_{}", cx.link_meta.crateid.name,
2121 cx.link_meta.crateid.version_or_default(), cx.link_meta.crate_hash);
2122 let llglobal = name.with_c_str(|buf| {
2123 unsafe {
2124 llvm::LLVMAddGlobal(cx.metadata_llmod, val_ty(llconst).to_ref(), buf)
2125 }
2126 });
2127 unsafe {
2128 llvm::LLVMSetInitializer(llglobal, llconst);
2129 cx.sess().targ_cfg.target_strs.meta_sect_name.with_c_str(|buf| {
2130 llvm::LLVMSetSection(llglobal, buf)
2131 });
2132 }
2133 return metadata;
2134 }
2135
2136 pub fn trans_crate(krate: ast::Crate,
2137 analysis: CrateAnalysis,
2138 output: &OutputFilenames) -> (ty::ctxt, CrateTranslation) {
2139 let CrateAnalysis { ty_cx: tcx, exp_map2, reachable, .. } = analysis;
2140
2141 // Before we touch LLVM, make sure that multithreading is enabled.
2142 unsafe {
2143 use sync::one::{Once, ONCE_INIT};
2144 static mut INIT: Once = ONCE_INIT;
2145 static mut POISONED: bool = false;
2146 INIT.doit(|| {
2147 if llvm::LLVMStartMultithreaded() != 1 {
2148 // use an extra bool to make sure that all future usage of LLVM
2149 // cannot proceed despite the Once not running more than once.
2150 POISONED = true;
2151 }
2152 });
2153
2154 if POISONED {
2155 tcx.sess.bug("couldn't enable multi-threaded LLVM");
2156 }
2157 }
2158
2159 let link_meta = link::build_link_meta(&krate, output.out_filestem);
2160
2161 // Append ".rs" to crate name as LLVM module identifier.
2162 //
2163 // LLVM code generator emits a ".file filename" directive
2164 // for ELF backends. Value of the "filename" is set as the
2165 // LLVM module identifier. Due to a LLVM MC bug[1], LLVM
2166 // crashes if the module identifer is same as other symbols
2167 // such as a function name in the module.
2168 // 1. http://llvm.org/bugs/show_bug.cgi?id=11479
2169 let mut llmod_id = link_meta.crateid.name.clone();
2170 llmod_id.push_str(".rs");
2171
2172 let ccx = CrateContext::new(llmod_id.as_slice(), tcx, exp_map2,
2173 Sha256::new(), link_meta, reachable);
2174 {
2175 let _icx = push_ctxt("text");
2176 trans_mod(&ccx, &krate.module);
2177 }
2178
2179 glue::emit_tydescs(&ccx);
2180 if ccx.sess().opts.debuginfo != NoDebugInfo {
2181 debuginfo::finalize(&ccx);
2182 }
2183
2184 // Translate the metadata.
2185 let metadata = write_metadata(&ccx, &krate);
2186 if ccx.sess().trans_stats() {
2187 println!("--- trans stats ---");
2188 println!("n_static_tydescs: {}", ccx.stats.n_static_tydescs.get());
2189 println!("n_glues_created: {}", ccx.stats.n_glues_created.get());
2190 println!("n_null_glues: {}", ccx.stats.n_null_glues.get());
2191 println!("n_real_glues: {}", ccx.stats.n_real_glues.get());
2192
2193 println!("n_fns: {}", ccx.stats.n_fns.get());
2194 println!("n_monos: {}", ccx.stats.n_monos.get());
2195 println!("n_inlines: {}", ccx.stats.n_inlines.get());
2196 println!("n_closures: {}", ccx.stats.n_closures.get());
2197 println!("fn stats:");
2198 ccx.stats.fn_stats.borrow_mut().sort_by(|&(_, _, insns_a), &(_, _, insns_b)| {
2199 insns_b.cmp(&insns_a)
2200 });
2201 for tuple in ccx.stats.fn_stats.borrow().iter() {
2202 match *tuple {
2203 (ref name, ms, insns) => {
2204 println!("{} insns, {} ms, {}", insns, ms, *name);
2205 }
2206 }
2207 }
2208 }
2209 if ccx.sess().count_llvm_insns() {
2210 for (k, v) in ccx.stats.llvm_insns.borrow().iter() {
2211 println!("{:7u} {}", *v, *k);
2212 }
2213 }
2214
2215 let llcx = ccx.llcx;
2216 let link_meta = ccx.link_meta.clone();
2217 let llmod = ccx.llmod;
2218
2219 let mut reachable: Vec<~str> = ccx.reachable.iter().filter_map(|id| {
2220 ccx.item_symbols.borrow().find(id).map(|s| s.to_owned())
2221 }).collect();
2222
2223 // Make sure that some other crucial symbols are not eliminated from the
2224 // module. This includes the main function, the crate map (used for debug
2225 // log settings and I/O), and finally the curious rust_stack_exhausted
2226 // symbol. This symbol is required for use by the libmorestack library that
2227 // we link in, so we must ensure that this symbol is not internalized (if
2228 // defined in the crate).
2229 reachable.push("main".to_owned());
2230 reachable.push("rust_stack_exhausted".to_owned());
2231
2232 // referenced from .eh_frame section on some platforms
2233 reachable.push("rust_eh_personality".to_owned());
2234 reachable.push("rust_eh_personality_catch".to_owned()); // referenced from rt/rust_try.ll
2235
2236 let metadata_module = ccx.metadata_llmod;
2237 let formats = ccx.tcx.dependency_formats.borrow().clone();
2238
2239 (ccx.tcx, CrateTranslation {
2240 context: llcx,
2241 module: llmod,
2242 link: link_meta,
2243 metadata_module: metadata_module,
2244 metadata: metadata,
2245 reachable: reachable,
2246 crate_formats: formats,
2247 })
2248 }
librustc/middle/trans/base.rs:844:1-844:1 -fn- definition:
pub fn trans_external_path(ccx: &CrateContext, did: ast::DefId, t: ty::t) -> ValueRef {
let name = csearch::get_symbol(&ccx.sess().cstore, did);
match ty::get(t).sty {
references:- 3librustc/middle/trans/callee.rs:
417: // External reference.
418: trans_external_path(ccx, def_id, fn_tpt.ty)
419: }
librustc/middle/trans/consts.rs:
621: let ty = csearch::get_type(cx.tcx(), def_id).ty;
622: (base::trans_external_path(cx, def_id, ty), true)
623: } else {
librustc/middle/trans/base.rs:
1791: start_def_id).ty;
1792: trans_external_path(ccx, start_def_id, start_fn_type)
1793: };
librustc/middle/trans/base.rs:1458:13-1458:13 -fn- definition:
// function.
pub fn trans_fn(ccx: &CrateContext,
decl: &ast::FnDecl,
references:- 71601: let llfn = get_item_val(ccx, item.id);
1602: trans_fn(ccx,
1603: decl,
librustc/middle/trans/meth.rs:
68: let llfn = get_item_val(ccx, method.id);
69: trans_fn(ccx, method.decl, method.body,
70: llfn, None, method.id, []);
librustc/middle/trans/foreign.rs:
557: base::set_llvm_fn_attrs(attrs, llfn);
558: base::trans_fn(ccx, decl, body, llfn, None, id, []);
559: llfn
librustc/middle/trans/inline.rs:
133: let llfn = get_item_val(ccx, mth.id);
134: trans_fn(ccx, mth.decl, mth.body, llfn, None, mth.id, []);
135: }
librustc/middle/trans/monomorphize.rs:
226: set_llvm_fn_attrs(i.attrs.as_slice(), d);
227: trans_fn(ccx, decl, body, d, Some(&psubsts), fn_id.node, []);
228: d
--
269: set_llvm_fn_attrs(mth.attrs.as_slice(), d);
270: trans_fn(ccx, mth.decl, mth.body, d, Some(&psubsts), mth.id, []);
271: d
--
277: set_llvm_fn_attrs(mth.attrs.as_slice(), d);
278: trans_fn(ccx, mth.decl, mth.body, d, Some(&psubsts), mth.id, []);
279: d
librustc/middle/trans/base.rs:532:50-532:50 -fn- definition:
// NB: This produces an i1, not a Rust bool (i8).
pub fn compare_scalar_types<'a>(
cx: &'a Block<'a>,
references:- 5librustc/middle/trans/_match.rs:
1683: let Result {bcx, val: llge} =
1684: compare_scalar_types(
1685: bcx, test_val,
--
1687: let Result {bcx, val: llle} =
1688: compare_scalar_types(
1689: bcx, test_val, vend,
librustc/middle/trans/expr.rs:
1329: } else if ty::type_is_scalar(rhs_t) {
1330: let cmpr = base::compare_scalar_types(bcx, lhs, rhs, rhs_t, op);
1331: bcx = cmpr.bcx;
librustc/middle/trans/_match.rs:
1676: lower_bound(Result {bcx, val}) => {
1677: compare_scalar_types(
1678: bcx, test_val, val,
librustc/middle/trans/base.rs:1308:32-1308:32 -fn- definition:
// and builds the return block.
pub fn finish_fn<'a>(fcx: &'a FunctionContext<'a>,
last_bcx: &'a Block<'a>) {
references:- 41556: finish_fn(&fcx, bcx);
1557: }
librustc/middle/trans/reflect.rs:
312: };
313: finish_fn(&fcx, bcx);
314: llfdecl
librustc/middle/trans/glue.rs:
475: let bcx = helper(bcx, llrawptr0, t);
476: finish_fn(&fcx, bcx);
librustc/middle/trans/base.rs:657:55-657:55 -fn- definition:
// Iterates through the elements of a structural type.
pub fn iter_structural_ty<'r,
'b>(
references:- 3librustc/middle/trans/glue.rs:
348: ty::type_is_structural(t) {
349: iter_structural_ty(bcx, v0, t, drop_ty)
350: } else {
librustc/middle/trans/base.rs:554:67-554:67 -fn- definition:
// A helper function to do the actual comparison of scalar values.
pub fn compare_scalar_values<'a>(
cx: &'a Block<'a>,
references:- 5539: -> Result<'a> {
540: let f = |a| Result::new(cx, compare_scalar_values(cx, lhs, rhs, a, op));
librustc/middle/trans/_match.rs:
1732: let llle =
1733: compare_scalar_values(
1734: bcx, test_val, vend,
librustc/middle/trans/base.rs:1071:1-1071:1 -fn- definition:
pub fn alloc_ty(bcx: &Block, t: ty::t, name: &str) -> ValueRef {
let _icx = push_ctxt("alloc_ty");
let ccx = bcx.ccx();
references:- 4librustc/middle/trans/_match.rs:
2105: // Allocate memory on stack for the binding.
2106: let llval = alloc_ty(bcx, var_ty, bcx.ident(ident));
librustc/middle/trans/closure.rs:
152: let cbox_ty = tuplify_box_ty(tcx, cdata_ty);
153: let llbox = alloc_ty(bcx, cbox_ty, "__closure");
154: Result::new(bcx, llbox)
librustc/middle/trans/callee.rs:
595: if !type_is_zero_size(ccx, ret_ty) {
596: Some(alloc_ty(bcx, ret_ty, "__llret"))
597: } else {
librustc/middle/trans/closure.rs:
269: let env_pointer_alloca = if bcx.sess().opts.debuginfo == FullDebugInfo {
270: let alloc = alloc_ty(bcx, ty::mk_mut_ptr(bcx.tcx(), cdata_ty), "__debuginfo_env_ptr");
271: Store(bcx, llcdata, alloc);
librustc/middle/trans/base.rs:667:4-667:4 -fn- definition:
fn iter_variant<'r,
'b>(
cx: &'b Block<'b>,
references:- 2723: (_match::single, None) => {
724: cx = iter_variant(cx, &*repr, av, &**variants.get(0),
725: substs.tps.as_slice(), f);
--
746: let variant_cx =
747: iter_variant(variant_cx,
748: &*repr,
librustc/middle/trans/base.rs:1693:1-1693:1 -fn- definition:
fn finish_register_fn(ccx: &CrateContext, sp: Span, sym: ~str, node_id: ast::NodeId,
llfn: ValueRef) {
ccx.item_symbols.borrow_mut().insert(node_id, sym);
references:- 21725: sym);
1726: finish_register_fn(ccx, sp, sym, node_id, llfn);
1727: llfn
--
1740: let llfn = decl_fn(ccx.llmod, sym, cc, fn_ty, output);
1741: finish_register_fn(ccx, sp, sym, node_id, llfn);
1742: llfn
librustc/middle/trans/base.rs:1706:1-1706:1 -fn- definition:
fn register_fn(ccx: &CrateContext,
sp: Span,
sym: ~str,
references:- 42073: let llfn = register_fn(ccx, m.span, sym, id, mty);
2074: set_llvm_fn_attrs(m.attrs.as_slice(), llfn);
librustc/middle/trans/base.rs:1010:1-1010:1 -fn- definition:
pub fn call_memcpy(cx: &Block, dst: ValueRef, src: ValueRef, n_bytes: ValueRef, align: u32) {
let _icx = push_ctxt("call_memcpy");
let ccx = cx.ccx();
references:- 41033: let llalign = llalign_of_min(ccx, llty);
1034: call_memcpy(bcx, dst, src, llsz, llalign as u32);
1035: } else {
librustc/middle/trans/tvec.rs:
329: let llcstr = C_cstr(bcx.ccx(), (*s).clone(), false);
330: base::call_memcpy(bcx,
331: lldest,
librustc/middle/trans/intrinsic.rs:
438: let llsize = llsize_of(ccx, llintype);
439: call_memcpy(bcx, lldestptr, llsrcptr, llsize, 1);
440: RetVoid(bcx);
librustc/middle/trans/foreign.rs:
424: debug!("llrust_size={:?}", llrust_size);
425: base::call_memcpy(bcx, llretptr_i8, llscratch_i8,
426: C_uint(ccx, llrust_size as uint), llalign as u32);
librustc/middle/trans/base.rs:1766:4-1766:4 -fn- definition:
fn create_entry_fn(ccx: &CrateContext,
rust_main: ValueRef,
use_start_lang_item: bool) {
references:- 21759: session::EntryMain => {
1760: create_entry_fn(ccx, main_llfn, true);
1761: }
1762: session::EntryStart => create_entry_fn(ccx, main_llfn, false),
1763: session::EntryNone => {} // Do nothing.
librustc/middle/trans/base.rs:1259:30-1259:30 -fn- definition:
// appropriate lvalue datums.
pub fn create_datums_for_fn_args(fcx: &FunctionContext,
arg_tys: &[ty::t])
references:- 31402: let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
1403: let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
--
1539: let arg_datums = create_datums_for_fn_args(&fcx, arg_tys.as_slice());
librustc/middle/trans/closure.rs:
440: let args = create_datums_for_fn_args(&fcx,
441: ty::ty_fn_args(closure_ty)
librustc/middle/trans/base.rs:993:1-993:1 -fn- definition:
pub fn with_cond<'a>(
bcx: &'a Block<'a>,
val: ValueRef,
references:- 9839: };
840: with_cond(cx, is_zero, |bcx| {
841: controlflow::trans_fail(bcx, span, InternedString::new(text))
librustc/middle/trans/_match.rs:
1383: return with_cond(bcx, Not(bcx, val), |bcx| {
1384: // Guard does not match: free the values we copied,
librustc/middle/trans/glue.rs:
285: ty::ty_vec(mt, None) => {
286: with_cond(bcx, not_null, |bcx| {
287: let bcx = tvec::make_drop_glue_unboxed(bcx, llbox, mt.ty);
--
335: let env = PointerCast(bcx, env, env_ptr_ty);
336: with_cond(bcx, IsNotNull(bcx, env), |bcx| {
337: let dtor_ptr = GEPi(bcx, env, [0u, abi::box_field_tydesc]);
librustc/middle/trans/expr.rs:
491: let expected = Call(bcx, expect, [bounds_check, C_i1(ccx, false)], []);
492: let bcx = with_cond(bcx, expected, |bcx| {
493: controlflow::trans_fail_bounds_check(bcx, index_expr.span, ix_val, len)
librustc/middle/trans/glue.rs:
291: ty::ty_str => {
292: with_cond(bcx, not_null, |bcx| {
293: let unit_ty = ty::sequence_element_type(bcx.tcx(), t);
librustc/middle/trans/base.rs:563:4-563:4 -fn- definition:
fn die(cx: &Block) -> ! {
cx.sess().bug("compare_scalar_values: must be a comparison operator");
}
references:- 4608: ast::BiGe => lib::llvm::IntUGE,
609: _ => die(cx)
610: };
librustc/middle/trans/base.rs:362:1-362:1 -fn- definition:
pub fn malloc_raw_dyn_managed<'a>(
bcx: &'a Block<'a>,
t: ty::t,
references:- 2librustc/middle/trans/expr.rs:
1200: let ty = type_of::type_of(bcx.ccx(), contents_ty);
1201: let Result {bcx, val: bx} = malloc_raw_dyn_managed(bcx, contents_ty, MallocFnLangItem,
1202: llsize_of(bcx.ccx(), ty));
librustc/middle/trans/closure.rs:
148: // we treat proc as @ here, which isn't ideal
149: malloc_raw_dyn_managed(bcx, cdata_ty, ClosureExchangeMallocFnLangItem, size)
150: }
librustc/middle/trans/base.rs:1358:13-1358:13 -fn- definition:
// returned.
pub fn trans_closure(ccx: &CrateContext,
decl: &ast::FnDecl,
references:- 21469: let output_type = ty::ty_fn_ret(ty::node_id_to_type(ccx.tcx(), id));
1470: trans_closure(ccx, decl, body, llfndecl,
1471: param_substs, id, attrs, output_type, |bcx| bcx);
librustc/middle/trans/closure.rs:
369: build_closure(bcx, freevar_mode, &freevars, store);
370: trans_closure(ccx, decl, body, llfn,
371: bcx.fcx.param_substs, id,
librustc/middle/trans/base.rs:207:97-207:97 -fn- definition:
// only use this for foreign function ABIs and glue, use `get_extern_rust_fn` for Rust functions
pub fn get_extern_fn(externs: &mut ExternMap, llmod: ModuleRef,
name: &str, cc: lib::llvm::CallConv,
references:- 3861: let llty = type_of_fn_from_ty(ccx, t);
862: get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod,
863: name, cconv, llty, fn_ty.sig.output)
librustc/middle/trans/foreign.rs:
220: let llfn = base::get_extern_fn(&mut *ccx.externs.borrow_mut(),
221: ccx.llmod,
librustc/middle/trans/base.rs:
512: get_extern_fn(&mut *ccx.externs.borrow_mut(), ccx.llmod, name,
513: lib::llvm::CCallConv, llty, ty::mk_nil())
librustc/middle/trans/base.rs:881:1-881:1 -fn- definition:
pub fn invoke<'a>(
bcx: &'a Block<'a>,
llfn: ValueRef,
references:- 2librustc/middle/trans/glue.rs:
269: let (_, bcx) = invoke(bcx, dtor_addr, args, [], None);
librustc/middle/trans/callee.rs:
693: // Invoke the actual rust fn and update bcx/llresult.
694: let (llret, b) = base::invoke(bcx,
695: llfn,
librustc/middle/trans/base.rs:102:1-102:1 -struct- definition:
pub struct _InsnCtxt { _x: () }
impl Drop for _InsnCtxt {
fn drop(&mut self) {
references:- 3120: }
121: _InsnCtxt { _x: () }
122: }
librustc/middle/trans/base.rs:1473:1-1473:1 -fn- definition:
pub fn trans_enum_variant(ccx: &CrateContext,
_enum_id: ast::NodeId,
variant: &ast::Variant,
references:- 21568: let llfn = get_item_val(ccx, variant.node.id);
1569: trans_enum_variant(ccx, id, variant, args.as_slice(),
1570: disr_val, None, llfn);
librustc/middle/trans/monomorphize.rs:
253: ast::TupleVariantKind(ref args) => {
254: trans_enum_variant(ccx,
255: parent,
librustc/middle/trans/base.rs:1827:1-1827:1 -fn- definition:
fn exported_name(ccx: &CrateContext, id: ast::NodeId,
ty: ty::t, attrs: &[ast::Attribute]) -> ~str {
match attr::first_attr_value_str_by_name(attrs, "export_name") {
references:- 42038: let ty = ty::node_id_to_type(ccx.tcx(), ctor_id);
2039: let sym = exported_name(ccx,
2040: id,
--
2071: let sym = exported_name(ccx, id, mty, m.attrs.as_slice());
librustc/middle/trans/base.rs:1080:1-1080:1 -fn- definition:
pub fn alloca(cx: &Block, ty: Type, name: &str) -> ValueRef {
alloca_maybe_zeroed(cx, ty, name, false)
}
references:- 111076: assert!(!ty::type_has_params(t));
1077: let val = alloca(bcx, ty, name);
1078: return val;
librustc/middle/trans/_match.rs:
1857: ast::BindByRef(_) => {
1858: llmatch = alloca(bcx, llvariable_ty, bcx.ident(ident));
1859: trmode = TrByRef;
librustc/middle/trans/tvec.rs:
529: // i = 0
530: let i = alloca(loop_bcx, bcx.ccx().int_type, "__i");
531: Store(loop_bcx, C_uint(bcx.ccx(), 0), i);
librustc/middle/trans/foreign.rs:
415: // bitcasting to the struct type yields invalid cast errors.
416: let llscratch = base::alloca(bcx, llforeign_ret_ty, "__cast");
417: Store(bcx, llforeign_retval, llscratch);
librustc/middle/trans/cleanup.rs:
681: None => {
682: let addr = base::alloca(pad_bcx, common::val_ty(llretval), "");
683: self.personality.set(Some(addr));
librustc/middle/trans/glue.rs:
125: let _icx = push_ctxt("drop_ty_immediate");
126: let vp = alloca(bcx, type_of(bcx.ccx(), t), "");
127: Store(bcx, v, vp);
librustc/middle/trans/_match.rs:
1252: Store(cx, lhs, scratch_lhs);
1253: let scratch_rhs = alloca(cx, val_ty(rhs), "__rhs");
1254: Store(cx, rhs, scratch_rhs);
librustc/middle/trans/base.rs:783:1-783:1 -fn- definition:
pub fn cast_shift_rhs(op: ast::BinOp,
lhs: ValueRef,
rhs: ValueRef,
references:- 2778: lhs: ValueRef, rhs: ValueRef) -> ValueRef {
779: cast_shift_rhs(op, lhs, rhs,
780: |a, b| unsafe { llvm::LLVMConstTrunc(a, b.to_ref()) },
librustc/middle/trans/base.rs:813:1-813:1 -fn- definition:
pub fn fail_if_zero<'a>(
cx: &'a Block<'a>,
span: Span,
references:- 2librustc/middle/trans/expr.rs:
1307: // Only zero-check integers; fp %0 is NaN
1308: bcx = base::fail_if_zero(bcx, binop_expr.span,
1309: op, rhs, rhs_t);
librustc/middle/trans/base.rs:1136:30-1136:30 -fn- definition:
// returned function context.
pub fn new_fn_ctxt<'a>(ccx: &'a CrateContext,
llfndecl: ValueRef,
references:- 61381: let arena = TypedArena::new();
1382: let fcx = new_fn_ctxt(ccx,
1383: llfndecl,
--
1532: let arena = TypedArena::new();
1533: let fcx = new_fn_ctxt(ccx, llfndecl, ctor_id, false, result_ty,
1534: param_substs.map(|s| &*s), None, &arena);
librustc/middle/trans/closure.rs:
435: let arena = TypedArena::new();
436: let fcx = new_fn_ctxt(ccx, llfn, -1, true, f.sig.output, None, None, &arena);
437: init_function(&fcx, true, f.sig.output);
librustc/middle/trans/reflect.rs:
292: let arena = TypedArena::new();
293: let fcx = new_fn_ctxt(ccx, llfdecl, -1, false,
294: ty::mk_u64(), None, None, &arena);
librustc/middle/trans/glue.rs:
458: let arena = TypedArena::new();
459: let fcx = new_fn_ctxt(ccx, llfn, -1, false, ty::mk_nil(), None, None, &arena);
librustc/middle/trans/intrinsic.rs:
193: let arena = TypedArena::new();
194: let fcx = new_fn_ctxt(ccx, decl, item.id, false, output_type,
195: Some(&*substs), Some(item.span), &arena);
librustc/middle/trans/base.rs:1591:1-1591:1 -fn- definition:
pub fn trans_item(ccx: &CrateContext, item: &ast::Item) {
let _icx = push_ctxt("trans_item");
match item.node {
references:- 51587: fn visit_item(&mut self, i: &ast::Item, _:()) {
1588: trans_item(self.ccx, i);
1589: }
--
1689: for item in m.items.iter() {
1690: trans_item(ccx, *item);
1691: }
librustc/middle/trans/inline.rs:
109: }
110: trans_item(ccx, item);
111: local_def(my_id)
librustc/middle/trans/controlflow.rs:
62: }
63: ast::DeclItem(i) => trans_item(cx.fcx.ccx, i)
64: }
librustc/middle/trans/base.rs:1505:1-1505:1 -fn- definition:
fn trans_enum_variant_or_tuple_like_struct(ccx: &CrateContext,
ctor_id: ast::NodeId,
disr: ty::Disr,
references:- 21483: trans_enum_variant_or_tuple_like_struct(
1484: ccx,
--
1498: trans_enum_variant_or_tuple_like_struct(
1499: ccx,
librustc/middle/trans/base.rs:451:1-451:1 -fn- definition:
pub fn set_always_inline(f: ValueRef) {
lib::llvm::SetFunctionAttribute(f, lib::llvm::AlwaysInlineAttribute)
}
references:- 2436: InlineHint => set_inline_hint(llfn),
437: InlineAlways => set_always_inline(llfn),
438: InlineNever => set_no_inline(llfn),
librustc/middle/trans/intrinsic.rs:
198: set_always_inline(fcx.llfn);
librustc/middle/trans/base.rs:1667:1-1667:1 -fn- definition:
pub fn trans_struct_def(ccx: &CrateContext, struct_def: @ast::StructDef) {
// If this is a tuple-like struct, translate the constructor.
match struct_def.ctor_id {
references:- 21652: if !generics.is_type_parameterized() {
1653: trans_struct_def(ccx, struct_def);
1654: }
librustc/middle/trans/base.rs:431:1-431:1 -fn- definition:
pub fn set_llvm_fn_attrs(attrs: &[ast::Attribute], llfn: ValueRef) {
use syntax::attr::*;
// Set the inline hint if there is one
references:- 71948: };
1949: set_llvm_fn_attrs(i.attrs.as_slice(), llfn);
1950: llfn
--
2073: let llfn = register_fn(ccx, m.span, sym, id, mty);
2074: set_llvm_fn_attrs(m.attrs.as_slice(), llfn);
2075: llfn
librustc/middle/trans/foreign.rs:
556: ps);
557: base::set_llvm_fn_attrs(attrs, llfn);
558: base::trans_fn(ccx, decl, body, llfn, None, id, []);
librustc/middle/trans/monomorphize.rs:
225: let d = mk_lldecl();
226: set_llvm_fn_attrs(i.attrs.as_slice(), d);
227: trans_fn(ccx, decl, body, d, Some(&psubsts), fn_id.node, []);
--
276: let d = mk_lldecl();
277: set_llvm_fn_attrs(mth.attrs.as_slice(), d);
278: trans_fn(ccx, mth.decl, mth.body, d, Some(&psubsts), mth.id, []);
librustc/middle/trans/base.rs:
228: csearch::get_item_attrs(&ccx.sess().cstore, did, |meta_items| {
229: set_llvm_fn_attrs(meta_items.iter().map(|&x| attr::mk_attr(x))
230: .collect::<Vec<_>>().as_slice(), f)
librustc/middle/trans/base.rs:219:1-219:1 -fn- definition:
fn get_extern_rust_fn(ccx: &CrateContext, inputs: &[ty::t], output: ty::t,
name: &str, did: ast::DefId) -> ValueRef {
match ccx.externs.borrow().find_equiv(&name) {
references:- 2851: Some(Rust) | Some(RustIntrinsic) => {
852: get_extern_rust_fn(ccx,
853: fn_ty.sig.inputs.as_slice(),
--
867: ty::ty_closure(ref f) => {
868: get_extern_rust_fn(ccx,
869: f.sig.inputs.as_slice(),
librustc/middle/trans/base.rs:332:1-332:1 -fn- definition:
fn require_alloc_fn(bcx: &Block, info_ty: ty::t, it: LangItem) -> ast::DefId {
match bcx.tcx().lang_items.require(it) {
Ok(id) => id,
references:- 2372: let langcall = require_alloc_fn(bcx, t, alloc_fn);
librustc/middle/trans/base.rs:199:91-199:91 -fn- definition:
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
pub fn decl_cdecl_fn(llmod: ModuleRef,
name: &str,
references:- 96librustc/middle/trans/glue.rs:
librustc/middle/trans/context.rs:
librustc/middle/trans/base.rs:427:1-427:1 -fn- definition:
pub fn set_inline_hint(f: ValueRef) {
lib::llvm::SetFunctionAttribute(f, lib::llvm::InlineHintAttribute)
}
references:- 6435: match find_inline_attr(attrs) {
436: InlineHint => set_inline_hint(llfn),
437: InlineAlways => set_always_inline(llfn),
--
2022: };
2023: set_inline_hint(llfn);
2024: llfn
librustc/middle/trans/closure.rs:
359: // set an inline hint for all closures
360: set_inline_hint(llfn);
librustc/middle/trans/monomorphize.rs:
250: let d = mk_lldecl();
251: set_inline_hint(d);
252: match v.node.kind {
--
288: let d = mk_lldecl();
289: set_inline_hint(d);
290: base::trans_tuple_struct(ccx,
librustc/middle/trans/base.rs:
2045: sym, ctor_id, ty);
2046: set_inline_hint(llfn);
2047: llfn
librustc/middle/trans/base.rs:345:1-345:1 -fn- definition:
pub fn malloc_raw_dyn<'a>(bcx: &'a Block<'a>,
ptr_ty: ty::t,
size: ValueRef)
references:- 2librustc/middle/trans/expr.rs:
1175: let real_box_ty = ty::mk_uniq(bcx.tcx(), contents_ty);
1176: let Result { bcx, val } = malloc_raw_dyn(bcx, real_box_ty, size);
1177: // Unique boxes do not allocate for zero-size types. The standard library
librustc/middle/trans/tvec.rs:
281: let Result { bcx: bcx, val: val } = malloc_raw_dyn(bcx, vec_ty, vecsize);
282: Store(bcx, fill, GEPi(bcx, val, [0u, abi::vec_elt_fill]));
librustc/middle/trans/base.rs:1053:50-1053:50 -fn- definition:
// `mov [byte ptr foo],0` in the generated code.)
fn memzero(b: &Builder, llptr: ValueRef, ty: Type) {
let _icx = push_ctxt("memzero");
references:- 21096: b.position_before(cx.fcx.alloca_insert_pt.get().unwrap());
1097: memzero(&b, p, ty);
1098: }
librustc/middle/trans/base.rs:1490:1-1490:1 -fn- definition:
pub fn trans_tuple_struct(ccx: &CrateContext,
_fields: &[ast::StructField],
ctor_id: ast::NodeId,
references:- 2librustc/middle/trans/monomorphize.rs:
289: set_inline_hint(d);
290: base::trans_tuple_struct(ccx,
291: struct_def.fields.as_slice(),
librustc/middle/trans/base.rs:
1674: let llfndecl = get_item_val(ccx, ctor_id);
1675: trans_tuple_struct(ccx, struct_def.fields.as_slice(),
1676: ctor_id, None, llfndecl);
librustc/middle/trans/base.rs:1039:1-1039:1 -fn- definition:
pub fn zero_mem(cx: &Block, llptr: ValueRef, t: ty::t) {
if cx.unreachable.get() { return; }
let _icx = push_ctxt("zero_mem");
references:- 2librustc/middle/trans/_match.rs:
2035: bcx, p_id, path, BindLocal, scope, (),
2036: |(), bcx, llval, ty| { zero_mem(bcx, llval, ty); bcx });
2037: });
librustc/middle/trans/datum.rs:
247: // cancel cleanup of affine values by zeroing out
248: let () = zero_mem(bcx, val, ty);
249: bcx
librustc/middle/trans/base.rs:653:1-653:1 -NK_AS_STR_TODO- definition:
pub type val_and_ty_fn<'r,'b> =
|&'b Block<'b>, ValueRef, ty::t|: 'r -> &'b Block<'b>;
// Iterates through the elements of a structural type.
references:- 2662: t: ty::t,
663: f: val_and_ty_fn<'r,'b>)
664: -> &'b Block<'b> {
--
673: tps: &[ty::t],
674: f: val_and_ty_fn<'r,'b>)
675: -> &'b Block<'b> {
librustc/middle/trans/base.rs:114:1-114:1 -fn- definition:
pub fn push_ctxt(s: &'static str) -> _InsnCtxt {
debug!("new InsnCtxt: {}", s);
match task_local_insn_key.get() {
references:- 126librustc/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/cleanup.rs:
librustc/middle/trans/inline.rs:
librustc/middle/trans/monomorphize.rs:
librustc/middle/trans/controlflow.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/base.rs:
librustc/middle/trans/base.rs:123:1-123:1 -struct- definition:
pub struct StatRecorder<'a> {
ccx: &'a CrateContext,
name: Option<~str>,
references:- 4138: let istart = ccx.stats.n_llvm_insns.get();
139: StatRecorder {
140: ccx: ccx,
--
149: impl<'a> Drop for StatRecorder<'a> {
150: fn drop(&mut self) {
librustc/middle/trans/base.rs:394:1-394:1 -fn- definition:
pub fn get_tydesc(ccx: &CrateContext, t: ty::t) -> Rc<tydesc_info> {
match ccx.tydescs.borrow().find(&t) {
Some(inf) => return inf.clone(),
references:- 2librustc/middle/trans/intrinsic.rs:
327: let tp_ty = *substs.tys.get(0);
328: let static_ti = get_tydesc(ccx, tp_ty);
329: glue::lazily_emit_visit_glue(ccx, &*static_ti);
librustc/middle/trans/reflect.rs:
76: let bcx = self.bcx;
77: let static_ti = get_tydesc(bcx.ccx(), t);
78: glue::lazily_emit_visit_glue(bcx.ccx(), &*static_ti);
librustc/middle/trans/base.rs:2066:1-2066:1 -fn- definition:
fn register_method(ccx: &CrateContext, id: ast::NodeId,
m: &ast::Method) -> ValueRef {
let mty = ty::node_id_to_type(ccx.tcx(), id);
references:- 21976: ast::Provided(m) => {
1977: register_method(ccx, id, m)
1978: }
--
1982: ast_map::NodeMethod(m) => {
1983: register_method(ccx, id, m)
1984: }
librustc/middle/trans/base.rs:1253:38-1253:38 -NK_AS_STR_TODO- definition:
// work around bizarre resolve errors
pub type RvalueDatum = datum::Datum<datum::Rvalue>;
pub type LvalueDatum = datum::Datum<datum::Lvalue>;
references:- 21261: arg_tys: &[ty::t])
1262: -> Vec<RvalueDatum> {
1263: let _icx = push_ctxt("create_datums_for_fn_args");
--
1278: args: &[ast::Arg],
1279: arg_datums: Vec<RvalueDatum> )
1280: -> &'a Block<'a> {
librustc/middle/trans/base.rs:469:62-469:62 -fn- definition:
// silently mangles such symbols, breaking our linkage model.
pub fn note_unique_llvm_symbol(ccx: &CrateContext, sym: ~str) {
if ccx.all_llvm_symbols.borrow().contains(&sym) {
references:- 2librustc/middle/trans/glue.rs:
420: });
421: note_unique_llvm_symbol(ccx, name);
--
442: let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty, ty::mk_nil());
443: note_unique_llvm_symbol(ccx, fn_nm);
444: return llfn;
librustc/middle/trans/base.rs:165:91-165:91 -fn- definition:
// only use this for foreign function ABIs and glue, use `decl_rust_fn` for Rust functions
fn decl_fn(llmod: ModuleRef, name: &str, cc: lib::llvm::CallConv,
ty: Type, output: ty::t) -> ValueRef {
references:- 3203: output: ty::t) -> ValueRef {
204: decl_fn(llmod, name, lib::llvm::CCallConv, ty, output)
205: }
--
214: }
215: let f = decl_fn(llmod, name, cc, ty, output);
216: externs.insert(name.to_owned(), f);
--
1740: let llfn = decl_fn(ccx.llmod, sym, cc, fn_ty, output);
1741: finish_register_fn(ccx, sp, sym, node_id, llfn);
librustc/middle/trans/base.rs:298:1-298:1 -fn- definition:
pub fn decl_internal_rust_fn(ccx: &CrateContext, has_env: bool,
inputs: &[ty::t], output: ty::t,
name: &str) -> ValueRef {
references:- 5librustc/middle/trans/closure.rs:
415: let llfn = if is_local {
416: decl_internal_rust_fn(ccx,
417: true,
librustc/middle/trans/foreign.rs:
552: let llfn = base::decl_internal_rust_fn(ccx,
553: false,
librustc/middle/trans/reflect.rs:
291: let llfdecl = decl_internal_rust_fn(ccx, false, [opaqueptrty], ty::mk_u64(), sym);
292: let arena = TypedArena::new();
librustc/middle/trans/monomorphize.rs:
210: let mk_lldecl = || {
211: let lldecl = decl_internal_rust_fn(ccx, false,
212: f.sig.inputs.as_slice(),
librustc/middle/trans/base.rs:1084:1-1084:1 -fn- definition:
pub fn alloca_maybe_zeroed(cx: &Block, ty: Type, name: &str, zero: bool) -> ValueRef {
let _icx = push_ctxt("alloca");
if cx.unreachable.get() {
references:- 31081: pub fn alloca(cx: &Block, ty: Type, name: &str) -> ValueRef {
1082: alloca_maybe_zeroed(cx, ty, name, false)
1083: }
librustc/middle/trans/datum.rs:
132: let llty = type_of::type_of(bcx.ccx(), ty);
133: let scratch = alloca_maybe_zeroed(bcx, llty, name, zero);
--
156: let llty = type_of::type_of(bcx.ccx(), ty);
157: let scratch = alloca_maybe_zeroed(bcx, llty, name, false);
158: Datum(scratch, ty, Rvalue(ByRef))
librustc/middle/trans/base.rs:1845:1-1845:1 -fn- definition:
pub fn get_item_val(ccx: &CrateContext, id: ast::NodeId) -> ValueRef {
debug!("get_item_val(id=`{:?}`)", id);
match ccx.item_vals.borrow().find_copy(&id) {
references:- 141596: if abi != Rust {
1597: let llfndecl = get_item_val(ccx, item.id);
1598: foreign::trans_rust_fn_with_foreign_abi(
--
1787: let start_fn = if start_def_id.krate == ast::LOCAL_CRATE {
1788: get_item_val(ccx, start_def_id.node)
1789: } else {
librustc/middle/trans/meth.rs:
67: if method.generics.ty_params.len() == 0u {
68: let llfn = get_item_val(ccx, method.id);
69: trans_fn(ccx, method.decl, method.body,
librustc/middle/trans/inline.rs:
132: if num_type_params == 0 {
133: let llfn = get_item_val(ccx, mth.id);
134: trans_fn(ccx, mth.decl, mth.body, llfn, None, mth.id, []);
librustc/middle/trans/monomorphize.rs:
121: // Foreign externs don't have to be monomorphized.
122: return (get_item_val(ccx, fn_id.node), true);
123: }
librustc/middle/trans/callee.rs:
414: // Internal reference.
415: get_item_val(ccx, def_id.node)
416: } else {
librustc/middle/trans/expr.rs:
531: // non-C-like enums.
532: let val = base::get_item_val(bcx.ccx(), did.node);
533: let pty = type_of::type_of(bcx.ccx(), const_ty).ptr_to();
librustc/middle/trans/consts.rs:
683: let _icx = push_ctxt("trans_const");
684: let g = base::get_item_val(ccx, id);
685: // At this point, get_item_val has already translated the
librustc/middle/trans/base.rs:
501: } else if did.krate == ast::LOCAL_CRATE {
502: get_item_val(ccx, did.node)
503: } else {
librustc/middle/trans/base.rs:1581:1-1581:1 -struct- definition:
pub struct TransItemVisitor<'a> {
pub ccx: &'a CrateContext,
}
references:- 71611: // items in blocks and such.
1612: let mut v = TransItemVisitor{ ccx: ccx };
1613: v.visit_block(body, ());
--
1660: // metadata time comes around.
1661: let mut v = TransItemVisitor{ ccx: ccx };
1662: visit::walk_item(&mut v, item, ());
librustc/middle/trans/meth.rs:
59: if !generics.ty_params.is_empty() {
60: let mut v = TransItemVisitor{ ccx: ccx };
61: for method in methods.iter() {
librustc/middle/trans/controlflow.rs:
139: Some(elexpr) => {
140: let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx };
141: trans.visit_expr(elexpr, ());
--
148: } else {
149: let mut trans = TransItemVisitor { ccx: bcx.fcx.ccx } ;
150: trans.visit_block(thn, ());
librustc/middle/trans/base.rs:
1586: impl<'a> Visitor<()> for TransItemVisitor<'a> {
1587: fn visit_item(&mut self, i: &ast::Item, _:()) {
librustc/middle/trans/meth.rs:
71: } else {
72: let mut v = TransItemVisitor{ ccx: ccx };
73: visit::walk_method_helper(&mut v, *method, ());
librustc/middle/trans/base.rs:236:1-236:1 -fn- definition:
pub fn decl_rust_fn(ccx: &CrateContext, has_env: bool,
inputs: &[ty::t], output: ty::t,
name: &str) -> ValueRef {
references:- 41721: let llfn = decl_rust_fn(ccx,
1722: false,
librustc/middle/trans/closure.rs:
421: } else {
422: decl_rust_fn(ccx, true, f.sig.inputs.as_slice(), f.sig.output, name)
423: };
librustc/middle/trans/base.rs:
301: name: &str) -> ValueRef {
302: let llfn = decl_rust_fn(ccx, has_env, inputs, output, name);
303: lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
librustc/middle/trans/base.rs:1686:27-1686:27 -fn- definition:
// and control visibility.
pub fn trans_mod(ccx: &CrateContext, m: &ast::Mod) {
let _icx = push_ctxt("trans_mod");
references:- 22175: let _icx = push_ctxt("text");
2176: trans_mod(&ccx, &krate.module);
2177: }
librustc/middle/trans/base.rs:1199:49-1199:49 -fn- definition:
/// and allocating space for the return pointer.
pub fn init_function<'a>(fcx: &'a FunctionContext<'a>,
skip_retptr: bool,
references:- 61534: param_substs.map(|s| &*s), None, &arena);
1535: init_function(&fcx, false, result_ty);
librustc/middle/trans/closure.rs:
436: let fcx = new_fn_ctxt(ccx, llfn, -1, true, f.sig.output, None, None, &arena);
437: init_function(&fcx, true, f.sig.output);
438: let bcx = fcx.entry_bcx.borrow().clone().unwrap();
librustc/middle/trans/intrinsic.rs:
195: Some(&*substs), Some(item.span), &arena);
196: init_function(&fcx, true, output_type);
librustc/middle/trans/reflect.rs:
294: ty::mk_u64(), None, None, &arena);
295: init_function(&fcx, false, ty::mk_u64());
librustc/middle/trans/glue.rs:
461: init_function(&fcx, false, ty::mk_nil());
librustc/middle/trans/base.rs:
1389: &arena);
1390: init_function(&fcx, false, output_type);