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