2011-06-01 11:34:52 -07:00
|
|
|
// trans.rs: Translate the completed AST to the LLVM IR.
|
|
|
|
//
|
|
|
|
// Some functions here, such as trans_block and trans_expr, return a value --
|
|
|
|
// the result of the translation to LLVM -- while others, such as trans_fn,
|
2012-01-13 10:58:31 +01:00
|
|
|
// trans_impl, and trans_item, are called only for the side effect of adding a
|
2011-06-01 11:34:52 -07:00
|
|
|
// particular definition to the LLVM IR output we're producing.
|
2011-06-01 16:33:03 -07:00
|
|
|
//
|
|
|
|
// Hopefully useful general knowledge about trans:
|
2011-06-07 17:54:22 -07:00
|
|
|
//
|
2011-06-01 16:33:03 -07:00
|
|
|
// * There's no way to find out the ty::t type of a ValueRef. Doing so
|
|
|
|
// would be "trying to get the eggs out of an omelette" (credit:
|
|
|
|
// pcwalton). You can, instead, find out its TypeRef by calling val_ty,
|
|
|
|
// but many TypeRefs correspond to one ty::t; for instance, tup(int, int,
|
|
|
|
// int) and rec(x=int, y=int, z=int) will have the same TypeRef.
|
2011-12-13 16:25:51 -08:00
|
|
|
|
2012-09-04 11:54:36 -07:00
|
|
|
use libc::{c_uint, c_ulonglong};
|
|
|
|
use std::{map, time, list};
|
2012-09-10 15:38:28 -07:00
|
|
|
use std::map::HashMap;
|
2012-09-04 11:54:36 -07:00
|
|
|
use driver::session;
|
|
|
|
use session::session;
|
|
|
|
use syntax::attr;
|
2012-09-18 11:46:39 -07:00
|
|
|
use back::{link, abi, upcall};
|
2012-09-04 11:54:36 -07:00
|
|
|
use syntax::{ast, ast_util, codemap, ast_map};
|
2012-10-05 17:31:46 -07:00
|
|
|
use ast_util::{def_id_of_def, local_def, path_to_ident};
|
2012-09-04 11:54:36 -07:00
|
|
|
use syntax::visit;
|
|
|
|
use syntax::codemap::span;
|
|
|
|
use syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str};
|
|
|
|
use pat_util::*;
|
|
|
|
use visit::vt;
|
|
|
|
use util::common::is_main_name;
|
|
|
|
use lib::llvm::{llvm, mk_target_data, mk_type_names};
|
|
|
|
use lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
|
|
|
|
use lib::llvm::{True, False};
|
2012-09-18 11:46:39 -07:00
|
|
|
use link::{mangle_internal_name_by_type_only,
|
2011-09-12 16:13:28 -07:00
|
|
|
mangle_internal_name_by_seq,
|
|
|
|
mangle_internal_name_by_path,
|
|
|
|
mangle_internal_name_by_path_and_seq,
|
|
|
|
mangle_exported_name};
|
2012-09-04 11:54:36 -07:00
|
|
|
use metadata::{csearch, cstore, decoder, encoder};
|
|
|
|
use metadata::common::link_meta;
|
|
|
|
use util::ppaux;
|
|
|
|
use util::ppaux::{ty_to_str, ty_to_short_str};
|
|
|
|
use syntax::diagnostic::expect;
|
2012-08-28 15:54:45 -07:00
|
|
|
use util::common::indenter;
|
2011-06-07 17:54:22 -07:00
|
|
|
|
2012-09-04 11:54:36 -07:00
|
|
|
use build::*;
|
|
|
|
use shape::*;
|
|
|
|
use type_of::*;
|
|
|
|
use common::*;
|
|
|
|
use syntax::ast_map::{path, path_mod, path_name};
|
|
|
|
use syntax::parse::token::special_idents;
|
2011-08-09 16:42:55 -07:00
|
|
|
|
2012-09-04 11:54:36 -07:00
|
|
|
use std::smallintmap;
|
|
|
|
use option::{is_none, is_some};
|
2012-03-03 17:49:23 -08:00
|
|
|
|
2012-08-15 18:46:55 -07:00
|
|
|
struct icx_popper {
|
2012-09-06 19:40:15 -07:00
|
|
|
ccx: @crate_ctxt,
|
2012-06-22 11:53:25 -07:00
|
|
|
drop {
|
|
|
|
if self.ccx.sess.count_llvm_insns() {
|
2012-09-27 22:20:47 -07:00
|
|
|
self.ccx.stats.llvm_insn_ctxt.pop();
|
2012-06-22 11:53:25 -07:00
|
|
|
}
|
2012-03-22 13:44:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-09-05 15:58:43 -07:00
|
|
|
fn icx_popper(ccx: @crate_ctxt) -> icx_popper {
|
|
|
|
icx_popper {
|
|
|
|
ccx: ccx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-11 15:00:40 -07:00
|
|
|
trait get_insn_ctxt {
|
2012-08-14 16:45:43 -07:00
|
|
|
fn insn_ctxt(s: &str) -> icx_popper;
|
2012-07-11 15:00:40 -07:00
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl @crate_ctxt: get_insn_ctxt {
|
2012-08-14 16:45:43 -07:00
|
|
|
fn insn_ctxt(s: &str) -> icx_popper {
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("new insn_ctxt: %s", s);
|
2012-05-17 21:53:49 -07:00
|
|
|
if self.sess.count_llvm_insns() {
|
2012-09-26 17:33:34 -07:00
|
|
|
self.stats.llvm_insn_ctxt.push(str::from_slice(s));
|
2012-03-22 13:44:20 -07:00
|
|
|
}
|
|
|
|
icx_popper(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl block: get_insn_ctxt {
|
2012-08-14 16:45:43 -07:00
|
|
|
fn insn_ctxt(s: &str) -> icx_popper {
|
2012-03-22 13:44:20 -07:00
|
|
|
self.ccx().insn_ctxt(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 18:10:06 -07:00
|
|
|
impl fn_ctxt: get_insn_ctxt {
|
2012-08-14 16:45:43 -07:00
|
|
|
fn insn_ctxt(s: &str) -> icx_popper {
|
2012-03-22 13:44:20 -07:00
|
|
|
self.ccx.insn_ctxt(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-29 16:09:41 -07:00
|
|
|
fn log_fn_time(ccx: @crate_ctxt, name: ~str, start: time::Timespec,
|
|
|
|
end: time::Timespec) {
|
2012-02-09 11:50:54 +01:00
|
|
|
let elapsed = 1000 * ((end.sec - start.sec) as int) +
|
2012-04-02 21:41:24 -07:00
|
|
|
((end.nsec as int) - (start.nsec as int)) / 1000000;
|
2012-09-26 17:33:34 -07:00
|
|
|
ccx.stats.fn_times.push({ident: name, time: elapsed});
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
|
2012-07-13 22:57:48 -07:00
|
|
|
fn decl_fn(llmod: ModuleRef, name: ~str, cc: lib::llvm::CallConv,
|
2012-02-01 11:04:56 +01:00
|
|
|
llty: TypeRef) -> ValueRef {
|
2012-06-30 16:19:07 -07:00
|
|
|
let llfn: ValueRef = str::as_c_str(name, |buf| {
|
2012-02-01 11:04:56 +01:00
|
|
|
llvm::LLVMGetOrInsertFunction(llmod, buf, llty)
|
|
|
|
});
|
|
|
|
lib::llvm::SetFunctionCallConv(llfn, cc);
|
2012-08-01 17:30:05 -07:00
|
|
|
return llfn;
|
2010-09-23 17:16:34 -07:00
|
|
|
}
|
|
|
|
|
2012-07-13 22:57:48 -07:00
|
|
|
fn decl_cdecl_fn(llmod: ModuleRef, name: ~str, llty: TypeRef) -> ValueRef {
|
2012-08-01 17:30:05 -07:00
|
|
|
return decl_fn(llmod, name, lib::llvm::CCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2011-05-15 19:53:06 -04:00
|
|
|
// Only use this if you are going to actually define the function. It's
|
|
|
|
// not valid to simply declare a function as internal.
|
2012-07-13 22:57:48 -07:00
|
|
|
fn decl_internal_cdecl_fn(llmod: ModuleRef, name: ~str, llty: TypeRef) ->
|
2011-06-15 11:19:50 -07:00
|
|
|
ValueRef {
|
2011-09-27 18:42:06 -07:00
|
|
|
let llfn = decl_cdecl_fn(llmod, name, llty);
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
2012-08-01 17:30:05 -07:00
|
|
|
return llfn;
|
2011-03-26 19:14:07 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 15:38:28 -07:00
|
|
|
fn get_extern_fn(externs: HashMap<~str, ValueRef>,
|
2012-07-13 22:57:48 -07:00
|
|
|
llmod: ModuleRef, name: ~str,
|
2012-02-01 11:04:56 +01:00
|
|
|
cc: lib::llvm::CallConv, ty: TypeRef) -> ValueRef {
|
2012-08-01 17:30:05 -07:00
|
|
|
if externs.contains_key(name) { return externs.get(name); }
|
2011-07-27 14:19:39 +02:00
|
|
|
let f = decl_fn(llmod, name, cc, ty);
|
2011-08-26 21:34:56 -07:00
|
|
|
externs.insert(name, f);
|
2012-08-01 17:30:05 -07:00
|
|
|
return f;
|
2010-09-23 18:38:37 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 15:38:28 -07:00
|
|
|
fn get_extern_const(externs: HashMap<~str, ValueRef>, llmod: ModuleRef,
|
2012-07-13 22:57:48 -07:00
|
|
|
name: ~str, ty: TypeRef) -> ValueRef {
|
2012-08-01 17:30:05 -07:00
|
|
|
if externs.contains_key(name) { return externs.get(name); }
|
2012-06-30 16:19:07 -07:00
|
|
|
let c = str::as_c_str(name, |buf| llvm::LLVMAddGlobal(llmod, ty, buf));
|
2011-08-26 21:34:56 -07:00
|
|
|
externs.insert(name, c);
|
2012-08-01 17:30:05 -07:00
|
|
|
return c;
|
2011-03-25 17:59:45 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn get_simple_extern_fn(cx: block,
|
2012-09-10 15:38:28 -07:00
|
|
|
externs: HashMap<~str, ValueRef>,
|
2011-10-14 16:45:25 -07:00
|
|
|
llmod: ModuleRef,
|
2012-07-13 22:57:48 -07:00
|
|
|
name: ~str, n_args: int) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("get_simple_extern_fn");
|
2012-02-03 09:53:37 +01:00
|
|
|
let ccx = cx.fcx.ccx;
|
2012-03-12 15:52:30 -07:00
|
|
|
let inputs = vec::from_elem(n_args as uint, ccx.int_type);
|
2011-10-14 17:00:17 -07:00
|
|
|
let output = ccx.int_type;
|
2011-07-27 14:19:39 +02:00
|
|
|
let t = T_fn(inputs, output);
|
2012-08-01 17:30:05 -07:00
|
|
|
return get_extern_fn(externs, llmod, name, lib::llvm::CCallConv, t);
|
2011-03-25 17:59:45 -07:00
|
|
|
}
|
|
|
|
|
2012-09-10 15:38:28 -07:00
|
|
|
fn trans_foreign_call(cx: block, externs: HashMap<~str, ValueRef>,
|
2012-07-13 22:57:48 -07:00
|
|
|
llmod: ModuleRef, name: ~str, args: ~[ValueRef]) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_foreign_call");
|
2012-02-14 09:10:47 +01:00
|
|
|
let n = args.len() as int;
|
2012-06-26 16:18:37 -07:00
|
|
|
let llforeign: ValueRef =
|
2011-10-14 16:45:25 -07:00
|
|
|
get_simple_extern_fn(cx, externs, llmod, name, n);
|
2012-09-18 21:41:37 -07:00
|
|
|
return Call(cx, llforeign, args);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("umax");
|
2012-02-01 11:04:56 +01:00
|
|
|
let cond = ICmp(cx, lib::llvm::IntULT, a, b);
|
2012-08-01 17:30:05 -07:00
|
|
|
return Select(cx, cond, b, a);
|
2012-01-19 10:37:40 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("umin");
|
2012-02-01 11:04:56 +01:00
|
|
|
let cond = ICmp(cx, lib::llvm::IntULT, a, b);
|
2012-08-01 17:30:05 -07:00
|
|
|
return Select(cx, cond, a, b);
|
2012-01-19 10:37:40 -08:00
|
|
|
}
|
|
|
|
|
2012-01-05 10:44:59 -08:00
|
|
|
// Given a pointer p, returns a pointer sz(p) (i.e., inc'd by sz bytes).
|
|
|
|
// The type of the returned pointer is always i8*. If you care about the
|
|
|
|
// return type, use bump_ptr().
|
2012-02-17 13:17:40 +01:00
|
|
|
fn ptr_offs(bcx: block, base: ValueRef, sz: ValueRef) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("ptr_offs");
|
2012-01-05 10:44:59 -08:00
|
|
|
let raw = PointerCast(bcx, base, T_ptr(T_i8()));
|
2012-06-29 16:26:56 -07:00
|
|
|
InBoundsGEP(bcx, raw, ~[sz])
|
2011-01-18 15:38:35 -08:00
|
|
|
}
|
|
|
|
|
2011-08-01 15:08:16 -07:00
|
|
|
// Increment a pointer by a given amount and then cast it to be a pointer
|
|
|
|
// to a given type.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn bump_ptr(bcx: block, t: ty::t, base: ValueRef, sz: ValueRef) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("bump_ptr");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-01-05 10:44:59 -08:00
|
|
|
let bumped = ptr_offs(bcx, base, sz);
|
2012-03-12 10:05:15 +01:00
|
|
|
let typ = T_ptr(type_of(ccx, t));
|
|
|
|
PointerCast(bcx, bumped, typ)
|
2011-08-01 15:08:16 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
// Replacement for the LLVM 'GEP' instruction when field indexing into a enum.
|
2012-03-12 09:26:54 +01:00
|
|
|
// @llblobptr is the data part of a enum value; its actual type
|
2012-01-19 14:34:23 -08:00
|
|
|
// is meaningless, as it will be cast away.
|
2012-03-12 09:26:54 +01:00
|
|
|
fn GEP_enum(bcx: block, llblobptr: ValueRef, enum_id: ast::def_id,
|
2012-06-29 16:26:56 -07:00
|
|
|
variant_id: ast::def_id, ty_substs: ~[ty::t],
|
2012-03-23 14:45:47 +01:00
|
|
|
ix: uint) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("GEP_enum");
|
2012-03-12 09:26:54 +01:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let variant = ty::enum_variant_with_id(ccx.tcx, enum_id, variant_id);
|
2012-02-22 11:44:11 +01:00
|
|
|
assert ix < variant.args.len();
|
|
|
|
|
2012-06-30 16:19:07 -07:00
|
|
|
let arg_lltys = vec::map(variant.args, |aty| {
|
2012-09-21 18:43:30 -07:00
|
|
|
type_of(ccx, ty::subst_tps(ccx.tcx, ty_substs, *aty))
|
2012-03-12 09:26:54 +01:00
|
|
|
});
|
|
|
|
let typed_blobptr = PointerCast(bcx, llblobptr,
|
|
|
|
T_ptr(T_struct(arg_lltys)));
|
2012-08-27 12:16:37 -07:00
|
|
|
GEPi(bcx, typed_blobptr, [0u, ix])
|
2011-03-04 15:08:33 -08:00
|
|
|
}
|
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
// Returns a pointer to the body for the box. The box may be an opaque
|
|
|
|
// box. The result will be casted to the type of body_t, if it is statically
|
|
|
|
// known.
|
|
|
|
//
|
|
|
|
// The runtime equivalent is box_body() in "rust_internal.h".
|
2012-02-17 13:17:40 +01:00
|
|
|
fn opaque_box_body(bcx: block,
|
2012-04-13 19:07:47 -07:00
|
|
|
body_t: ty::t,
|
|
|
|
boxptr: ValueRef) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("opaque_box_body");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-01 18:52:08 -08:00
|
|
|
let boxptr = PointerCast(bcx, boxptr, T_ptr(T_box_header(ccx)));
|
2012-08-27 12:16:37 -07:00
|
|
|
let bodyptr = GEPi(bcx, boxptr, [1u]);
|
2012-03-12 10:05:15 +01:00
|
|
|
PointerCast(bcx, bodyptr, T_ptr(type_of(ccx, body_t)))
|
2012-02-01 18:52:08 -08:00
|
|
|
}
|
2012-02-01 18:50:19 -08:00
|
|
|
|
2012-06-13 18:00:17 -07:00
|
|
|
// malloc_raw_dyn: allocates a box to contain a given type, but with a
|
|
|
|
// potentially dynamic size.
|
|
|
|
fn malloc_raw_dyn(bcx: block, t: ty::t, heap: heap,
|
2012-08-28 15:54:45 -07:00
|
|
|
size: ValueRef) -> Result {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("malloc_raw");
|
2012-03-15 09:47:03 -04:00
|
|
|
let ccx = bcx.ccx();
|
2011-07-28 15:44:51 -07:00
|
|
|
|
2012-08-06 12:34:08 -07:00
|
|
|
let (mk_fn, rtcall) = match heap {
|
2012-08-03 19:59:04 -07:00
|
|
|
heap_shared => (ty::mk_imm_box, ~"malloc"),
|
|
|
|
heap_exchange => (ty::mk_imm_uniq, ~"exchange_malloc")
|
2012-06-06 18:22:49 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
// Grab the TypeRef type of box_ptr_ty.
|
|
|
|
let box_ptr_ty = mk_fn(bcx.tcx(), t);
|
|
|
|
let llty = type_of(ccx, box_ptr_ty);
|
2011-09-20 13:38:35 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
// Get the tydesc for the body:
|
2012-07-09 18:03:37 -07:00
|
|
|
let static_ti = get_tydesc(ccx, t);
|
2012-08-28 15:54:45 -07:00
|
|
|
glue::lazily_emit_all_tydesc_glue(ccx, static_ti);
|
2011-09-20 13:48:22 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
// Allocate space:
|
2012-07-17 10:48:19 -07:00
|
|
|
let tydesc = PointerCast(bcx, static_ti.tydesc, T_ptr(T_i8()));
|
|
|
|
let rval = alloca_zeroed(bcx, T_ptr(T_i8()));
|
2012-08-28 15:54:45 -07:00
|
|
|
let bcx = callee::trans_rtcall(bcx, rtcall, ~[tydesc, size],
|
|
|
|
expr::SaveIn(rval));
|
|
|
|
return rslt(bcx, PointerCast(bcx, Load(bcx, rval), llty));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get the type of a box in the default address space.
|
|
|
|
*
|
|
|
|
* Shared box pointers live in address space 1 so the GC strategy can find
|
|
|
|
* them. Before taking a pointer to the inside of a box it should be cast into
|
|
|
|
* address space 0. Otherwise the resulting (non-box) pointer will be in the
|
|
|
|
* wrong address space and thus be the wrong type.
|
|
|
|
*/
|
|
|
|
fn non_gc_box_cast(bcx: block, val: ValueRef) -> ValueRef {
|
|
|
|
debug!("non_gc_box_cast");
|
|
|
|
add_comment(bcx, ~"non_gc_box_cast");
|
|
|
|
assert(llvm::LLVMGetPointerAddressSpace(val_ty(val)) == gc_box_addrspace);
|
|
|
|
let non_gc_t = T_ptr(llvm::LLVMGetElementType(val_ty(val)));
|
|
|
|
PointerCast(bcx, val, non_gc_t)
|
2010-12-02 17:43:05 -08:00
|
|
|
}
|
|
|
|
|
2012-06-13 18:00:17 -07:00
|
|
|
// malloc_raw: expects an unboxed type and returns a pointer to
|
|
|
|
// enough space for a box of that type. This includes a rust_opaque_box
|
|
|
|
// header.
|
2012-08-28 15:54:45 -07:00
|
|
|
fn malloc_raw(bcx: block, t: ty::t, heap: heap) -> Result {
|
2012-06-13 18:00:17 -07:00
|
|
|
malloc_raw_dyn(bcx, t, heap, llsize_of(bcx.ccx(), type_of(bcx.ccx(), t)))
|
|
|
|
}
|
|
|
|
|
|
|
|
// malloc_general_dyn: usefully wraps malloc_raw_dyn; allocates a box,
|
2012-06-06 18:22:49 -07:00
|
|
|
// and pulls out the body
|
2012-07-17 10:48:19 -07:00
|
|
|
fn malloc_general_dyn(bcx: block, t: ty::t, heap: heap, size: ValueRef)
|
|
|
|
-> {bcx: block, box: ValueRef, body: ValueRef} {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("malloc_general");
|
2012-08-28 15:54:45 -07:00
|
|
|
let Result {bcx: bcx, val: llbox} = malloc_raw_dyn(bcx, t, heap, size);
|
2012-06-27 14:10:24 -07:00
|
|
|
let non_gc_box = non_gc_box_cast(bcx, llbox);
|
2012-08-27 12:16:37 -07:00
|
|
|
let body = GEPi(bcx, non_gc_box, [0u, abi::box_field_body]);
|
2012-08-01 17:30:05 -07:00
|
|
|
return {bcx: bcx, box: llbox, body: body};
|
2011-07-28 15:44:51 -07:00
|
|
|
}
|
2010-12-02 17:43:05 -08:00
|
|
|
|
2012-07-17 10:48:19 -07:00
|
|
|
fn malloc_general(bcx: block, t: ty::t, heap: heap)
|
|
|
|
-> {bcx: block, box: ValueRef, body: ValueRef} {
|
2012-06-26 13:50:43 -07:00
|
|
|
malloc_general_dyn(bcx, t, heap,
|
2012-06-26 12:58:58 -07:00
|
|
|
llsize_of(bcx.ccx(), type_of(bcx.ccx(), t)))
|
2012-05-21 18:36:52 -07:00
|
|
|
}
|
2012-07-17 10:48:19 -07:00
|
|
|
fn malloc_boxed(bcx: block, t: ty::t)
|
|
|
|
-> {bcx: block, box: ValueRef, body: ValueRef} {
|
2012-06-26 13:50:43 -07:00
|
|
|
malloc_general(bcx, t, heap_shared)
|
2012-06-26 12:58:58 -07:00
|
|
|
}
|
2012-07-17 10:48:19 -07:00
|
|
|
fn malloc_unique(bcx: block, t: ty::t)
|
|
|
|
-> {bcx: block, box: ValueRef, body: ValueRef} {
|
2012-06-26 13:50:43 -07:00
|
|
|
malloc_general(bcx, t, heap_exchange)
|
2012-05-21 18:36:52 -07:00
|
|
|
}
|
|
|
|
|
2010-12-20 10:23:37 -08:00
|
|
|
// Type descriptor and type glue stuff
|
|
|
|
|
2012-03-21 15:42:20 +01:00
|
|
|
fn get_tydesc_simple(ccx: @crate_ctxt, t: ty::t) -> ValueRef {
|
2012-07-09 18:03:37 -07:00
|
|
|
get_tydesc(ccx, t).tydesc
|
2012-02-17 15:45:38 +01:00
|
|
|
}
|
2011-08-17 19:11:01 -07:00
|
|
|
|
2012-07-09 18:03:37 -07:00
|
|
|
fn get_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
2012-08-06 12:34:08 -07:00
|
|
|
match ccx.tydescs.find(t) {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(inf) => inf,
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => {
|
2012-02-07 11:25:04 +01:00
|
|
|
ccx.stats.n_static_tydescs += 1u;
|
2012-08-28 15:54:45 -07:00
|
|
|
let inf = glue::declare_tydesc(ccx, t);
|
2012-04-19 16:19:53 -07:00
|
|
|
ccx.tydescs.insert(t, inf);
|
2012-06-28 10:49:51 -07:00
|
|
|
inf
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-12-20 15:23:24 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_no_inline(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, lib::llvm::NoInlineAttribute as c_ulonglong,
|
|
|
|
0u as c_ulonglong);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2012-04-25 15:38:56 -07:00
|
|
|
fn set_no_unwind(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, lib::llvm::NoUnwindAttribute as c_ulonglong,
|
|
|
|
0u as c_ulonglong);
|
2012-04-25 15:38:56 -07:00
|
|
|
}
|
|
|
|
|
2011-07-06 17:02:56 -07:00
|
|
|
// Tell LLVM to emit the information necessary to unwind the stack for the
|
|
|
|
// function f.
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_uwtable(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, lib::llvm::UWTableAttribute as c_ulonglong,
|
|
|
|
0u as c_ulonglong);
|
2011-05-24 13:47:27 -04:00
|
|
|
}
|
|
|
|
|
2012-03-02 10:05:30 -08:00
|
|
|
fn set_inline_hint(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, lib::llvm::InlineHintAttribute
|
|
|
|
as c_ulonglong, 0u as c_ulonglong);
|
2012-03-02 10:05:30 -08:00
|
|
|
}
|
|
|
|
|
2012-06-29 16:26:56 -07:00
|
|
|
fn set_inline_hint_if_appr(attrs: ~[ast::attribute],
|
2012-03-06 11:33:25 +01:00
|
|
|
llfn: ValueRef) {
|
2012-08-06 12:34:08 -07:00
|
|
|
match attr::find_inline_attr(attrs) {
|
2012-08-03 19:59:04 -07:00
|
|
|
attr::ia_hint => set_inline_hint(llfn),
|
|
|
|
attr::ia_always => set_always_inline(llfn),
|
|
|
|
attr::ia_never => set_no_inline(llfn),
|
|
|
|
attr::ia_none => { /* fallthrough */ }
|
2012-03-02 10:05:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn set_always_inline(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, lib::llvm::AlwaysInlineAttribute
|
|
|
|
as c_ulonglong, 0u as c_ulonglong);
|
2011-09-30 18:20:28 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn set_custom_stack_growth_fn(f: ValueRef) {
|
2012-06-07 14:37:36 -07:00
|
|
|
llvm::LLVMAddFunctionAttr(f, 0u as c_ulonglong, 1u as c_ulonglong);
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2012-02-03 15:15:28 +01:00
|
|
|
fn set_glue_inlining(f: ValueRef, t: ty::t) {
|
|
|
|
if ty::type_is_structural(t) {
|
2011-05-20 14:57:52 -07:00
|
|
|
set_no_inline(f);
|
2011-06-15 11:19:50 -07:00
|
|
|
} else { set_always_inline(f); }
|
2011-05-20 14:57:52 -07:00
|
|
|
}
|
|
|
|
|
2012-03-20 14:21:02 -07:00
|
|
|
// Double-check that we never ask LLVM to declare the same symbol twice. It
|
|
|
|
// silently mangles such symbols, breaking our linkage model.
|
2012-07-13 22:57:48 -07:00
|
|
|
fn note_unique_llvm_symbol(ccx: @crate_ctxt, sym: ~str) {
|
2012-03-20 14:21:02 -07:00
|
|
|
if ccx.all_llvm_symbols.contains_key(sym) {
|
2012-07-13 22:57:48 -07:00
|
|
|
ccx.sess.bug(~"duplicate LLVM symbol: " + sym);
|
2012-03-20 14:21:02 -07:00
|
|
|
}
|
|
|
|
ccx.all_llvm_symbols.insert(sym, ());
|
|
|
|
}
|
2011-05-20 14:57:52 -07:00
|
|
|
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2012-06-19 14:44:38 -07:00
|
|
|
fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id,
|
2012-06-29 16:26:56 -07:00
|
|
|
parent_id: ast::def_id, substs: ~[ty::t])
|
2012-03-08 21:16:04 +01:00
|
|
|
-> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_res_dtor");
|
2012-09-26 19:40:05 -07:00
|
|
|
if (substs.is_not_empty()) {
|
2012-04-18 13:46:21 +02:00
|
|
|
let did = if did.crate != ast::local_crate {
|
2012-08-28 15:54:45 -07:00
|
|
|
inline::maybe_instantiate_inline(ccx, did)
|
2012-04-18 13:46:21 +02:00
|
|
|
} else { did };
|
|
|
|
assert did.crate == ast::local_crate;
|
2012-08-28 15:54:45 -07:00
|
|
|
monomorphize::monomorphic_fn(ccx, did, substs, None, None).val
|
2012-04-18 13:46:21 +02:00
|
|
|
} else if did.crate == ast::local_crate {
|
|
|
|
get_item_val(ccx, did.node)
|
|
|
|
} else {
|
2012-06-24 15:09:57 -07:00
|
|
|
let tcx = ccx.tcx;
|
|
|
|
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
|
|
|
let class_ty = ty::subst_tps(tcx, substs,
|
|
|
|
ty::lookup_item_type(tcx, parent_id).ty);
|
|
|
|
let llty = type_of_dtor(ccx, class_ty);
|
|
|
|
get_extern_fn(ccx.externs, ccx.llmod, name, lib::llvm::CCallConv,
|
|
|
|
llty)
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
2011-06-28 16:14:01 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Structural comparison: a rather involved form of glue.
|
2012-07-13 22:57:48 -07:00
|
|
|
fn maybe_name_value(cx: @crate_ctxt, v: ValueRef, s: ~str) {
|
2012-01-12 17:59:49 +01:00
|
|
|
if cx.sess.opts.save_temps {
|
2012-06-30 16:19:07 -07:00
|
|
|
let _: () = str::as_c_str(s, |buf| llvm::LLVMSetValueName(v, buf));
|
2011-05-10 16:43:34 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-08-02 12:26:52 -07:00
|
|
|
// Used only for creating scalar comparison glue.
|
2012-01-19 17:56:05 -08:00
|
|
|
enum scalar_type { nil_type, signed_int, unsigned_int, floating_point, }
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn compare_scalar_types(cx: block, lhs: ValueRef, rhs: ValueRef,
|
2012-08-28 15:54:45 -07:00
|
|
|
t: ty::t, op: ast::binop) -> Result {
|
2012-06-30 16:19:07 -07:00
|
|
|
let f = |a| compare_scalar_values(cx, lhs, rhs, a, op);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-09-11 16:20:31 -07:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 15:54:45 -07:00
|
|
|
ty::ty_nil => rslt(cx, f(nil_type)),
|
|
|
|
ty::ty_bool | ty::ty_ptr(_) => rslt(cx, f(unsigned_int)),
|
|
|
|
ty::ty_int(_) => rslt(cx, f(signed_int)),
|
|
|
|
ty::ty_uint(_) => rslt(cx, f(unsigned_int)),
|
|
|
|
ty::ty_float(_) => rslt(cx, f(floating_point)),
|
|
|
|
ty::ty_type => {
|
|
|
|
rslt(
|
|
|
|
controlflow::trans_fail(
|
|
|
|
cx, None,
|
|
|
|
~"attempt to compare values of type type"),
|
|
|
|
C_nil())
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
// Should never get here, because t is scalar.
|
|
|
|
cx.sess().bug(~"non-scalar type passed to \
|
|
|
|
compare_scalar_types")
|
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-07-11 16:37:21 -05:00
|
|
|
// A helper function to do the actual comparison of scalar values.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn compare_scalar_values(cx: block, lhs: ValueRef, rhs: ValueRef,
|
2011-10-27 22:01:30 -07:00
|
|
|
nt: scalar_type, op: ast::binop) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("compare_scalar_values");
|
2012-02-17 13:17:40 +01:00
|
|
|
fn die_(cx: block) -> ! {
|
2012-07-13 22:57:48 -07:00
|
|
|
cx.tcx().sess.bug(~"compare_scalar_values: must be a\
|
2012-01-30 21:00:57 -08:00
|
|
|
comparison operator");
|
|
|
|
}
|
2012-06-19 19:34:01 -07:00
|
|
|
let die = fn@() -> ! { die_(cx) };
|
2012-08-06 12:34:08 -07:00
|
|
|
match nt {
|
2012-08-03 19:59:04 -07:00
|
|
|
nil_type => {
|
2011-07-27 14:19:39 +02:00
|
|
|
// We don't need to do actual comparisons for nil.
|
|
|
|
// () == () holds but () < () does not.
|
2012-08-06 12:34:08 -07:00
|
|
|
match op {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::eq | ast::le | ast::ge => return C_bool(true),
|
|
|
|
ast::ne | ast::lt | ast::gt => return C_bool(false),
|
2012-01-30 21:00:57 -08:00
|
|
|
// refinements would be nice
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => die()
|
2011-10-27 22:01:30 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
floating_point => {
|
2012-08-06 12:34:08 -07:00
|
|
|
let cmp = match op {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::eq => lib::llvm::RealOEQ,
|
|
|
|
ast::ne => lib::llvm::RealUNE,
|
|
|
|
ast::lt => lib::llvm::RealOLT,
|
|
|
|
ast::le => lib::llvm::RealOLE,
|
|
|
|
ast::gt => lib::llvm::RealOGT,
|
|
|
|
ast::ge => lib::llvm::RealOGE,
|
|
|
|
_ => die()
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
2012-08-01 17:30:05 -07:00
|
|
|
return FCmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
signed_int => {
|
2012-08-06 12:34:08 -07:00
|
|
|
let cmp = match op {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::eq => lib::llvm::IntEQ,
|
|
|
|
ast::ne => lib::llvm::IntNE,
|
|
|
|
ast::lt => lib::llvm::IntSLT,
|
|
|
|
ast::le => lib::llvm::IntSLE,
|
|
|
|
ast::gt => lib::llvm::IntSGT,
|
|
|
|
ast::ge => lib::llvm::IntSGE,
|
|
|
|
_ => die()
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
2012-08-01 17:30:05 -07:00
|
|
|
return ICmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
unsigned_int => {
|
2012-08-06 12:34:08 -07:00
|
|
|
let cmp = match op {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::eq => lib::llvm::IntEQ,
|
|
|
|
ast::ne => lib::llvm::IntNE,
|
|
|
|
ast::lt => lib::llvm::IntULT,
|
|
|
|
ast::le => lib::llvm::IntULE,
|
|
|
|
ast::gt => lib::llvm::IntUGT,
|
|
|
|
ast::ge => lib::llvm::IntUGE,
|
|
|
|
_ => die()
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
2012-08-01 17:30:05 -07:00
|
|
|
return ICmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
type val_pair_fn = fn@(block, ValueRef, ValueRef) -> block;
|
|
|
|
type val_and_ty_fn = fn@(block, ValueRef, ty::t) -> block;
|
2011-02-28 17:49:26 -08:00
|
|
|
|
2012-08-27 12:16:37 -07:00
|
|
|
fn load_inbounds(cx: block, p: ValueRef, idxs: &[uint]) -> ValueRef {
|
2012-08-01 17:30:05 -07:00
|
|
|
return Load(cx, GEPi(cx, p, idxs));
|
2011-07-05 14:19:19 -07:00
|
|
|
}
|
|
|
|
|
2012-08-27 12:16:37 -07:00
|
|
|
fn store_inbounds(cx: block, v: ValueRef, p: ValueRef, idxs: &[uint]) {
|
2011-10-26 17:09:07 -07:00
|
|
|
Store(cx, v, GEPi(cx, p, idxs));
|
2011-07-05 14:19:19 -07:00
|
|
|
}
|
|
|
|
|
2011-08-30 13:10:10 +02:00
|
|
|
// Iterates through the elements of a structural type.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn iter_structural_ty(cx: block, av: ValueRef, t: ty::t,
|
|
|
|
f: val_and_ty_fn) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("iter_structural_ty");
|
2012-03-22 13:44:20 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn iter_variant(cx: block, a_tup: ValueRef,
|
2012-06-25 20:00:46 -07:00
|
|
|
variant: ty::variant_info,
|
2012-06-29 16:26:56 -07:00
|
|
|
tps: ~[ty::t], tid: ast::def_id,
|
2012-02-17 13:17:40 +01:00
|
|
|
f: val_and_ty_fn) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("iter_variant");
|
2012-08-01 17:30:05 -07:00
|
|
|
if variant.args.len() == 0u { return cx; }
|
2011-07-27 14:19:39 +02:00
|
|
|
let fn_ty = variant.ctor_ty;
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut cx = cx;
|
2012-09-11 16:20:31 -07:00
|
|
|
match ty::get(fn_ty).sty {
|
2012-09-07 07:37:19 -07:00
|
|
|
ty::ty_fn(ref fn_ty) => {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut j = 0u;
|
2011-09-01 17:25:06 -07:00
|
|
|
let v_id = variant.id;
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(fn_ty.sig.inputs) |a| {
|
2012-03-23 14:45:47 +01:00
|
|
|
let llfldp_a = GEP_enum(cx, a_tup, tid, v_id, tps, j);
|
2012-04-18 21:26:25 -07:00
|
|
|
let ty_subst = ty::subst_tps(ccx.tcx, tps, a.ty);
|
2011-08-30 13:50:58 +02:00
|
|
|
cx = f(cx, llfldp_a, ty_subst);
|
2011-09-01 16:31:18 -07:00
|
|
|
j += 1u;
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => cx.tcx().sess.bug(~"iter_variant: not a function type")
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return cx;
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-07-13 15:44:09 -07:00
|
|
|
|
2011-09-17 10:18:30 -07:00
|
|
|
/*
|
|
|
|
Typestate constraint that shows the unimpl case doesn't happen?
|
|
|
|
*/
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut cx = cx;
|
2012-09-11 16:20:31 -07:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 15:54:45 -07:00
|
|
|
ty::ty_rec(*) | ty::ty_class(*) => {
|
|
|
|
do expr::with_field_tys(cx.tcx(), t) |_has_dtor, field_tys| {
|
|
|
|
for vec::eachi(field_tys) |i, field_ty| {
|
|
|
|
let llfld_a = GEPi(cx, av, struct_field(i));
|
|
|
|
cx = f(cx, llfld_a, field_ty.mt.ty);
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-24 14:04:38 -07:00
|
|
|
ty::ty_estr(ty::vstore_fixed(_)) |
|
|
|
|
ty::ty_evec(_, ty::vstore_fixed(_)) => {
|
2012-04-19 15:42:02 -07:00
|
|
|
let (base, len) = tvec::get_base_and_len(cx, av, t);
|
|
|
|
cx = tvec::iter_vec_raw(cx, base, t, len, f);
|
2012-04-09 17:32:49 -07:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
ty::ty_tup(args) => {
|
2012-06-30 16:19:07 -07:00
|
|
|
for vec::eachi(args) |i, arg| {
|
2012-08-27 12:16:37 -07:00
|
|
|
let llfld_a = GEPi(cx, av, [0u, i]);
|
2012-09-21 18:43:30 -07:00
|
|
|
cx = f(cx, llfld_a, *arg);
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
ty::ty_enum(tid, substs) => {
|
2012-02-21 14:20:18 +01:00
|
|
|
let variants = ty::enum_variants(cx.tcx(), tid);
|
2012-02-14 09:10:47 +01:00
|
|
|
let n_variants = (*variants).len();
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-01-25 14:34:31 +01:00
|
|
|
// Cast the enums to types we can GEP into.
|
2011-07-27 14:19:39 +02:00
|
|
|
if n_variants == 1u {
|
2012-08-01 17:30:05 -07:00
|
|
|
return iter_variant(cx, av, variants[0],
|
2012-04-18 21:26:25 -07:00
|
|
|
substs.tps, tid, f);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-01-25 14:34:31 +01:00
|
|
|
let llenumty = T_opaque_enum_ptr(ccx);
|
|
|
|
let av_enum = PointerCast(cx, av, llenumty);
|
2012-08-27 12:16:37 -07:00
|
|
|
let lldiscrim_a_ptr = GEPi(cx, av_enum, [0u, 0u]);
|
|
|
|
let llunion_a_ptr = GEPi(cx, av_enum, [0u, 1u]);
|
2011-08-30 09:59:30 +02:00
|
|
|
let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
// NB: we must hit the discriminant first so that structural
|
|
|
|
// comparison know not to proceed when the discriminants differ.
|
2012-02-21 14:20:18 +01:00
|
|
|
cx = f(cx, lldiscrim_a_ptr, ty::mk_int(cx.tcx()));
|
2012-07-13 22:57:48 -07:00
|
|
|
let unr_cx = sub_block(cx, ~"enum-iter-unr");
|
2011-08-30 09:59:30 +02:00
|
|
|
Unreachable(unr_cx);
|
2011-08-30 13:50:58 +02:00
|
|
|
let llswitch = Switch(cx, lldiscrim_a, unr_cx.llbb, n_variants);
|
2012-07-13 22:57:48 -07:00
|
|
|
let next_cx = sub_block(cx, ~"enum-iter-next");
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(*variants) |variant| {
|
2011-07-27 14:19:39 +02:00
|
|
|
let variant_cx =
|
2012-02-17 13:17:40 +01:00
|
|
|
sub_block(cx,
|
2012-07-13 22:57:48 -07:00
|
|
|
~"enum-iter-variant-" +
|
2012-01-10 14:50:40 -07:00
|
|
|
int::to_str(variant.disr_val, 10u));
|
|
|
|
AddCase(llswitch, C_int(ccx, variant.disr_val), variant_cx.llbb);
|
2012-03-15 09:47:03 -04:00
|
|
|
let variant_cx =
|
2012-09-18 21:41:37 -07:00
|
|
|
iter_variant(variant_cx, llunion_a_ptr, *variant,
|
2012-04-18 21:26:25 -07:00
|
|
|
substs.tps, tid, f);
|
2011-08-30 09:59:30 +02:00
|
|
|
Br(variant_cx, next_cx.llbb);
|
2010-12-01 17:08:46 -08:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return next_cx;
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => cx.sess().unimpl(~"type in iter_structural_ty")
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return cx;
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2012-02-21 21:01:33 -08:00
|
|
|
fn cast_shift_expr_rhs(cx: block, op: ast::binop,
|
|
|
|
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
cast_shift_rhs(op, lhs, rhs,
|
2012-06-30 16:19:07 -07:00
|
|
|
|a,b| Trunc(cx, a, b),
|
|
|
|
|a,b| ZExt(cx, a, b))
|
2012-02-21 21:01:33 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
fn cast_shift_const_rhs(op: ast::binop,
|
|
|
|
lhs: ValueRef, rhs: ValueRef) -> ValueRef {
|
|
|
|
cast_shift_rhs(op, lhs, rhs,
|
|
|
|
llvm::LLVMConstTrunc, llvm::LLVMConstZExt)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn cast_shift_rhs(op: ast::binop,
|
|
|
|
lhs: ValueRef, rhs: ValueRef,
|
|
|
|
trunc: fn(ValueRef, TypeRef) -> ValueRef,
|
|
|
|
zext: fn(ValueRef, TypeRef) -> ValueRef
|
|
|
|
) -> ValueRef {
|
|
|
|
// Shifts may have any size int on the rhs
|
|
|
|
if ast_util::is_shift_binop(op) {
|
|
|
|
let rhs_llty = val_ty(rhs);
|
|
|
|
let lhs_llty = val_ty(lhs);
|
|
|
|
let rhs_sz = llvm::LLVMGetIntTypeWidth(rhs_llty);
|
|
|
|
let lhs_sz = llvm::LLVMGetIntTypeWidth(lhs_llty);
|
|
|
|
if lhs_sz < rhs_sz {
|
|
|
|
trunc(rhs, lhs_llty)
|
|
|
|
} else if lhs_sz > rhs_sz {
|
2012-10-11 16:15:12 -07:00
|
|
|
// FIXME (#1877: If shifting by negative
|
2012-06-21 16:44:10 -07:00
|
|
|
// values becomes not undefined then this is wrong.
|
2012-02-21 21:01:33 -08:00
|
|
|
zext(rhs, lhs_llty)
|
|
|
|
} else {
|
|
|
|
rhs
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-14 15:32:20 -07:00
|
|
|
fn fail_if_zero(cx: block, span: span, divmod: ast::binop,
|
|
|
|
rhs: ValueRef, rhs_t: ty::t) -> block {
|
|
|
|
let text = if divmod == ast::div {
|
2012-07-13 22:57:48 -07:00
|
|
|
~"divide by zero"
|
2012-06-14 15:32:20 -07:00
|
|
|
} else {
|
2012-07-13 22:57:48 -07:00
|
|
|
~"modulo zero"
|
2012-06-14 15:32:20 -07:00
|
|
|
};
|
2012-09-11 16:20:31 -07:00
|
|
|
let is_zero = match ty::get(rhs_t).sty {
|
2012-08-28 15:54:45 -07:00
|
|
|
ty::ty_int(t) => {
|
|
|
|
let zero = C_integral(T_int_ty(cx.ccx(), t), 0u64, False);
|
|
|
|
ICmp(cx, lib::llvm::IntEQ, rhs, zero)
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
ty::ty_uint(t) => {
|
|
|
|
let zero = C_integral(T_uint_ty(cx.ccx(), t), 0u64, False);
|
|
|
|
ICmp(cx, lib::llvm::IntEQ, rhs, zero)
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => {
|
2012-08-28 15:54:45 -07:00
|
|
|
cx.tcx().sess.bug(~"fail-if-zero on unexpected type: " +
|
|
|
|
ty_to_str(cx.ccx().tcx, rhs_t));
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
};
|
|
|
|
do with_cond(cx, is_zero) |bcx| {
|
|
|
|
controlflow::trans_fail(bcx, Some(span), text)
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
fn null_env_ptr(bcx: block) -> ValueRef {
|
|
|
|
C_null(T_opaque_box_ptr(bcx.ccx()))
|
2012-03-14 15:16:46 -04:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
fn trans_external_path(ccx: @crate_ctxt, did: ast::def_id, t: ty::t)
|
|
|
|
-> ValueRef {
|
|
|
|
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
2012-09-11 16:20:31 -07:00
|
|
|
match ty::get(t).sty {
|
2012-08-28 15:54:45 -07:00
|
|
|
ty::ty_fn(_) => {
|
|
|
|
let llty = type_of_fn_from_ty(ccx, t);
|
|
|
|
return get_extern_fn(ccx.externs, ccx.llmod, name,
|
|
|
|
lib::llvm::CCallConv, llty);
|
2012-03-14 15:16:46 -04:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
_ => {
|
|
|
|
let llty = type_of(ccx, t);
|
|
|
|
return get_extern_const(ccx.externs, ccx.llmod, name, llty);
|
2012-03-14 15:16:46 -04:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
};
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
|
|
|
|
let _icx = ccx.insn_ctxt("lookup_discriminant");
|
|
|
|
match ccx.discrims.find(vid) {
|
|
|
|
None => {
|
|
|
|
// It's an external discriminant that we haven't seen yet.
|
|
|
|
assert (vid.crate != ast::local_crate);
|
|
|
|
let sym = csearch::get_symbol(ccx.sess.cstore, vid);
|
|
|
|
let gvar = str::as_c_str(sym, |buf| {
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
|
|
|
});
|
|
|
|
lib::llvm::SetLinkage(gvar, lib::llvm::ExternalLinkage);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
|
|
|
ccx.discrims.insert(vid, gvar);
|
|
|
|
return gvar;
|
|
|
|
}
|
|
|
|
Some(llval) => return llval,
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-29 16:26:56 -07:00
|
|
|
fn invoke(bcx: block, llfn: ValueRef, llargs: ~[ValueRef]) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("invoke_");
|
2012-08-01 17:30:05 -07:00
|
|
|
if bcx.unreachable { return bcx; }
|
2012-03-26 13:30:56 -07:00
|
|
|
if need_invoke(bcx) {
|
2012-07-13 22:57:48 -07:00
|
|
|
log(debug, ~"invoking");
|
|
|
|
let normal_bcx = sub_block(bcx, ~"normal return");
|
2012-03-26 13:30:56 -07:00
|
|
|
Invoke(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
|
2012-08-01 17:30:05 -07:00
|
|
|
return normal_bcx;
|
2012-03-26 13:30:56 -07:00
|
|
|
} else {
|
2012-07-13 22:57:48 -07:00
|
|
|
log(debug, ~"calling");
|
2012-03-26 13:30:56 -07:00
|
|
|
Call(bcx, llfn, llargs);
|
2012-08-01 17:30:05 -07:00
|
|
|
return bcx;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2012-03-26 13:30:56 -07:00
|
|
|
fn need_invoke(bcx: block) -> bool {
|
2012-06-29 12:31:23 -07:00
|
|
|
if (bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0) {
|
2012-08-01 17:30:05 -07:00
|
|
|
return false;
|
2012-06-29 12:31:23 -07:00
|
|
|
}
|
|
|
|
|
2012-07-23 16:00:19 -07:00
|
|
|
// Avoid using invoke if we are already inside a landing pad.
|
|
|
|
if bcx.is_lpad {
|
2012-08-01 17:30:05 -07:00
|
|
|
return false;
|
2012-07-23 16:00:19 -07:00
|
|
|
}
|
|
|
|
|
2012-03-26 13:30:56 -07:00
|
|
|
if have_cached_lpad(bcx) {
|
2012-08-01 17:30:05 -07:00
|
|
|
return true;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Walk the scopes to look for cleanups
|
|
|
|
let mut cur = bcx;
|
|
|
|
loop {
|
2012-08-06 12:34:08 -07:00
|
|
|
match cur.kind {
|
2012-08-03 19:59:04 -07:00
|
|
|
block_scope(inf) => {
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(inf.cleanups) |cleanup| {
|
2012-09-18 21:41:37 -07:00
|
|
|
match *cleanup {
|
2012-08-03 19:59:04 -07:00
|
|
|
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) => {
|
2012-03-26 13:30:56 -07:00
|
|
|
if cleanup_type == normal_exit_and_unwind {
|
2012-08-01 17:30:05 -07:00
|
|
|
return true;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
}
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
2012-08-06 12:34:08 -07:00
|
|
|
cur = match cur.parent {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(next) => next,
|
|
|
|
None => return false
|
2011-09-13 16:40:18 -07:00
|
|
|
}
|
|
|
|
}
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn have_cached_lpad(bcx: block) -> bool {
|
|
|
|
let mut res = false;
|
2012-06-30 16:19:07 -07:00
|
|
|
do in_lpad_scope_cx(bcx) |inf| {
|
2012-08-06 12:34:08 -07:00
|
|
|
match inf.landing_pad {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(_) => res = true,
|
|
|
|
None => res = false
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return res;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn in_lpad_scope_cx(bcx: block, f: fn(scope_info)) {
|
|
|
|
let mut bcx = bcx;
|
|
|
|
loop {
|
2012-08-06 12:34:08 -07:00
|
|
|
match bcx.kind {
|
2012-08-03 19:59:04 -07:00
|
|
|
block_scope(inf) => {
|
2012-09-21 19:37:57 -07:00
|
|
|
if inf.cleanups.len() > 0u || bcx.parent.is_none() {
|
2012-08-01 17:30:05 -07:00
|
|
|
f(inf); return;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
bcx = block_parent(bcx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_landing_pad(bcx: block) -> BasicBlockRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("get_landing_pad");
|
2011-09-13 16:10:39 -07:00
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
let mut cached = None, pad_bcx = bcx; // Guaranteed to be set below
|
2012-06-30 16:19:07 -07:00
|
|
|
do in_lpad_scope_cx(bcx) |inf| {
|
2012-02-17 11:18:14 +01:00
|
|
|
// If there is a valid landing pad still around, use it
|
2012-08-06 12:34:08 -07:00
|
|
|
match copy inf.landing_pad {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(target) => cached = Some(target),
|
|
|
|
None => {
|
2012-07-23 16:00:19 -07:00
|
|
|
pad_bcx = lpad_block(bcx, ~"unwind");
|
2012-08-20 12:23:37 -07:00
|
|
|
inf.landing_pad = Some(pad_bcx.llbb);
|
2012-03-26 12:39:20 +02:00
|
|
|
}
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
// Can't return from block above
|
2012-08-20 12:23:37 -07:00
|
|
|
match cached { Some(b) => return b, None => () }
|
2011-09-07 14:28:02 -07:00
|
|
|
// The landing pad return type (the type being propagated). Not sure what
|
|
|
|
// this represents but it's determined by the personality function and
|
|
|
|
// this is what the EH proposal example uses.
|
2012-06-29 16:26:56 -07:00
|
|
|
let llretty = T_struct(~[T_ptr(T_i8()), T_i32()]);
|
2011-09-07 14:28:02 -07:00
|
|
|
// The exception handling personality function. This is the C++
|
|
|
|
// personality function __gxx_personality_v0, wrapped in our naming
|
|
|
|
// convention.
|
2012-02-21 14:20:18 +01:00
|
|
|
let personality = bcx.ccx().upcalls.rust_personality;
|
2011-09-07 14:28:02 -07:00
|
|
|
// The only landing pad clause will be 'cleanup'
|
2012-02-15 13:57:29 +01:00
|
|
|
let llretval = LandingPad(pad_bcx, llretty, personality, 1u);
|
2011-09-07 14:28:02 -07:00
|
|
|
// The landing pad block is a cleanup
|
2012-02-15 13:57:29 +01:00
|
|
|
SetCleanup(pad_bcx, llretval);
|
2011-09-07 15:12:37 -07:00
|
|
|
|
2011-12-06 16:26:47 -08:00
|
|
|
// Because we may have unwound across a stack boundary, we must call into
|
|
|
|
// the runtime to figure out which stack segment we are on and place the
|
|
|
|
// stack limit back into the TLS.
|
2012-06-29 16:26:56 -07:00
|
|
|
Call(pad_bcx, bcx.ccx().upcalls.reset_stack_limit, ~[]);
|
2011-12-06 16:26:47 -08:00
|
|
|
|
2012-02-15 13:57:29 +01:00
|
|
|
// We store the retval in a function-central alloca, so that calls to
|
|
|
|
// Resume can find it.
|
2012-08-06 12:34:08 -07:00
|
|
|
match copy bcx.fcx.personality {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(addr) => Store(pad_bcx, llretval, addr),
|
|
|
|
None => {
|
2012-02-15 13:57:29 +01:00
|
|
|
let addr = alloca(pad_bcx, val_ty(llretval));
|
2012-08-20 12:23:37 -07:00
|
|
|
bcx.fcx.personality = Some(addr);
|
2012-02-15 13:57:29 +01:00
|
|
|
Store(pad_bcx, llretval, addr);
|
|
|
|
}
|
2011-09-07 15:12:37 -07:00
|
|
|
}
|
|
|
|
|
2012-02-15 13:57:29 +01:00
|
|
|
// Unwind all parent scopes, and finish with a Resume instr
|
2012-08-20 12:23:37 -07:00
|
|
|
cleanup_and_leave(pad_bcx, None, None);
|
2012-08-01 17:30:05 -07:00
|
|
|
return pad_bcx.llbb;
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
// Arranges for the value found in `*root_loc` to be dropped once the scope
|
|
|
|
// associated with `scope_id` exits. This is used to keep boxes live when
|
|
|
|
// there are extant region pointers pointing at the interior.
|
|
|
|
//
|
|
|
|
// Note that `root_loc` is not the value itself but rather a pointer to the
|
|
|
|
// value. Generally it in alloca'd value. The reason for this is that the
|
|
|
|
// value is initialized in an inner block but may be freed in some outer
|
|
|
|
// block, so an SSA value that is valid in the inner block may not be valid in
|
|
|
|
// the outer block. In fact, the inner block may not even execute. Rather
|
|
|
|
// than generate the full SSA form, we just use an alloca'd value.
|
|
|
|
fn add_root_cleanup(bcx: block, scope_id: ast::node_id,
|
|
|
|
root_loc: ValueRef, ty: ty::t) {
|
|
|
|
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("add_root_cleanup(bcx=%s, scope_id=%d, root_loc=%s, ty=%s)",
|
2012-05-14 20:32:29 -07:00
|
|
|
bcx.to_str(), scope_id, val_str(bcx.ccx().tn, root_loc),
|
2012-08-22 17:24:52 -07:00
|
|
|
ppaux::ty_to_str(bcx.ccx().tcx, ty));
|
2012-05-14 20:32:29 -07:00
|
|
|
|
|
|
|
let bcx_scope = find_bcx_for_scope(bcx, scope_id);
|
|
|
|
add_clean_temp_mem(bcx_scope, root_loc, ty);
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
|
|
|
|
let mut bcx_sid = bcx;
|
|
|
|
loop {
|
|
|
|
bcx_sid = match bcx_sid.node_info {
|
|
|
|
Some({id, _}) if id == scope_id => {
|
|
|
|
return bcx_sid
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
match bcx_sid.parent {
|
|
|
|
None => bcx.tcx().sess.bug(
|
|
|
|
fmt!("no enclosing scope with id %d", scope_id)),
|
|
|
|
Some(bcx_par) => bcx_par
|
|
|
|
}
|
|
|
|
}
|
2011-11-18 15:10:14 +01:00
|
|
|
}
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn do_spill(bcx: block, v: ValueRef, t: ty::t) -> ValueRef {
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_bot(t) {
|
2012-08-01 17:30:05 -07:00
|
|
|
return C_null(T_ptr(T_i8()));
|
2011-09-21 10:54:56 -07:00
|
|
|
}
|
2012-03-23 14:45:47 +01:00
|
|
|
let llptr = alloc_ty(bcx, t);
|
2011-09-02 15:12:27 -07:00
|
|
|
Store(bcx, v, llptr);
|
2012-08-01 17:30:05 -07:00
|
|
|
return llptr;
|
2011-09-02 15:12:27 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// Since this function does *not* root, it is the caller's responsibility to
|
|
|
|
// ensure that the referent is pointed to by a root.
|
2012-06-12 14:55:44 -07:00
|
|
|
// [Note-arg-mode]
|
|
|
|
// ++ mode is temporary, due to how borrowck treats enums. With hope,
|
|
|
|
// will go away anyway when we get rid of modes.
|
|
|
|
fn do_spill_noroot(++cx: block, v: ValueRef) -> ValueRef {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llptr = alloca(cx, val_ty(v));
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, v, llptr);
|
2012-08-01 17:30:05 -07:00
|
|
|
return llptr;
|
2011-04-12 12:06:20 -07:00
|
|
|
}
|
2010-12-03 13:03:07 -08:00
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn spill_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("spill_if_immediate");
|
2012-08-01 17:30:05 -07:00
|
|
|
if ty::type_is_immediate(t) { return do_spill(cx, v, t); }
|
|
|
|
return v;
|
2011-04-12 12:06:20 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn load_if_immediate(cx: block, v: ValueRef, t: ty::t) -> ValueRef {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("load_if_immediate");
|
2012-08-01 17:30:05 -07:00
|
|
|
if ty::type_is_immediate(t) { return Load(cx, v); }
|
|
|
|
return v;
|
2010-12-03 13:03:07 -08:00
|
|
|
}
|
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
fn trans_trace(bcx: block, sp_opt: Option<span>, trace_str: ~str) {
|
2012-08-01 17:30:05 -07:00
|
|
|
if !bcx.sess().trace() { return; }
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_trace");
|
2012-05-18 19:02:39 -07:00
|
|
|
add_comment(bcx, trace_str);
|
|
|
|
let V_trace_str = C_cstr(bcx.ccx(), trace_str);
|
2012-08-06 12:34:08 -07:00
|
|
|
let {V_filename, V_line} = match sp_opt {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(sp) => {
|
2012-05-18 19:02:39 -07:00
|
|
|
let sess = bcx.sess();
|
|
|
|
let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
|
|
|
|
{V_filename: C_cstr(bcx.ccx(), loc.file.name),
|
|
|
|
V_line: loc.line as int}
|
|
|
|
}
|
2012-08-20 12:23:37 -07:00
|
|
|
None => {
|
2012-07-13 22:57:48 -07:00
|
|
|
{V_filename: C_cstr(bcx.ccx(), ~"<runtime>"),
|
2012-05-18 19:02:39 -07:00
|
|
|
V_line: 0}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let V_trace_str = PointerCast(bcx, V_trace_str, T_ptr(T_i8()));
|
|
|
|
let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
|
2012-06-29 16:26:56 -07:00
|
|
|
let args = ~[V_trace_str, V_filename, C_int(ccx, V_line)];
|
2012-05-18 19:02:39 -07:00
|
|
|
Call(bcx, ccx.upcalls.trace, args);
|
|
|
|
}
|
|
|
|
|
2012-03-22 13:44:20 -07:00
|
|
|
fn build_return(bcx: block) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("build_return");
|
2012-03-22 13:44:20 -07:00
|
|
|
Br(bcx, bcx.fcx.llreturn);
|
|
|
|
}
|
2011-08-17 17:49:54 -07:00
|
|
|
|
2012-08-08 15:36:38 -07:00
|
|
|
fn ignore_lhs(_bcx: block, local: @ast::local) -> bool {
|
|
|
|
match local.node.pat.node {
|
|
|
|
ast::pat_wild => true, _ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn init_local(bcx: block, local: @ast::local) -> block {
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
debug!("init_local(bcx=%s, local.id=%?)",
|
|
|
|
bcx.to_str(), local.node.id);
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("init_local");
|
2012-02-02 12:37:17 +01:00
|
|
|
let ty = node_id_type(bcx, local.node.id);
|
2012-08-08 15:36:38 -07:00
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
debug!("ty=%s", bcx.ty_to_str(ty));
|
|
|
|
|
2012-08-08 15:36:38 -07:00
|
|
|
if ignore_lhs(bcx, local) {
|
|
|
|
// Handle let _ = e; just like e;
|
|
|
|
match local.node.init {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(init) => {
|
2012-08-28 15:54:45 -07:00
|
|
|
return expr::trans_into(bcx, init.expr, expr::Ignore);
|
2012-08-08 15:36:38 -07:00
|
|
|
}
|
2012-08-20 12:23:37 -07:00
|
|
|
None => { return bcx; }
|
2012-08-08 15:36:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-06 12:34:08 -07:00
|
|
|
let llptr = match bcx.fcx.lllocals.find(local.node.id) {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(local_mem(v)) => v,
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => { bcx.tcx().sess.span_bug(local.span,
|
2012-07-13 22:57:48 -07:00
|
|
|
~"init_local: Someone forgot to document why it's\
|
2012-01-30 21:00:57 -08:00
|
|
|
safe to assume local.node.init must be local_mem!");
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
2011-10-07 11:20:51 +02:00
|
|
|
};
|
2011-08-23 15:45:24 -07:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-08-06 12:34:08 -07:00
|
|
|
match local.node.init {
|
2012-08-28 15:54:45 -07:00
|
|
|
Some(init) => {
|
|
|
|
if init.op == ast::init_assign || !bcx.expr_is_lval(init.expr) {
|
|
|
|
bcx = expr::trans_into(bcx, init.expr, expr::SaveIn(llptr));
|
|
|
|
} else { // This is a move from an lval, perform an actual move
|
|
|
|
let init_datumblock = expr::trans_to_datum(bcx, init.expr);
|
|
|
|
bcx = init_datumblock.move_to(datum::INIT, llptr);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
zero_mem(bcx, llptr, ty);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2011-09-28 10:41:19 +02:00
|
|
|
// Make a note to drop this slot on the way out.
|
2012-08-28 15:54:45 -07:00
|
|
|
debug!("adding clean for %?/%s to bcx=%s",
|
|
|
|
local.node.id, bcx.ty_to_str(ty),
|
|
|
|
bcx.to_str());
|
2011-09-28 10:41:19 +02:00
|
|
|
add_clean(bcx, llptr, ty);
|
2012-08-28 15:54:45 -07:00
|
|
|
|
2012-08-01 17:30:05 -07:00
|
|
|
return alt::bind_irrefutable_pat(bcx, local.node.pat, llptr, false);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_stmt(cx: block, s: ast::stmt) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_stmt");
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("trans_stmt(%s)", stmt_to_str(s, cx.tcx().sess.intr()));
|
2012-02-01 18:52:08 -08:00
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if !cx.sess().no_asm_comments() {
|
2012-07-18 16:18:02 -07:00
|
|
|
add_span_comment(cx, s.span, stmt_to_str(s, cx.ccx().sess.intr()));
|
2011-12-06 14:02:06 -08:00
|
|
|
}
|
2011-11-14 14:03:20 -08:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = cx;
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(cx, s.span);
|
2011-12-19 02:52:21 -05:00
|
|
|
|
2012-08-06 12:34:08 -07:00
|
|
|
match s.node {
|
2012-08-28 15:54:45 -07:00
|
|
|
ast::stmt_expr(e, _) | ast::stmt_semi(e, _) => {
|
|
|
|
bcx = expr::trans_into(cx, e, expr::Ignore);
|
|
|
|
}
|
|
|
|
ast::stmt_decl(d, _) => {
|
|
|
|
match d.node {
|
|
|
|
ast::decl_local(locals) => {
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(locals) |local| {
|
2012-09-18 21:41:37 -07:00
|
|
|
bcx = init_local(bcx, *local);
|
2012-08-28 15:54:45 -07:00
|
|
|
if cx.sess().opts.extra_debuginfo {
|
2012-09-18 21:41:37 -07:00
|
|
|
debuginfo::create_local_var(bcx, *local);
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
}
|
2011-11-15 21:11:22 -05:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
ast::decl_item(i) => trans_item(cx.fcx.ccx, *i)
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
2011-11-15 21:11:22 -05:00
|
|
|
|
2012-08-01 17:30:05 -07:00
|
|
|
return bcx;
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// You probably don't want to use this one. See the
|
|
|
|
// next three functions instead.
|
2012-08-20 12:23:37 -07:00
|
|
|
fn new_block(cx: fn_ctxt, parent: Option<block>, +kind: block_kind,
|
|
|
|
is_lpad: bool, name: ~str, opt_node_info: Option<node_info>)
|
2012-07-23 16:00:19 -07:00
|
|
|
-> block {
|
2012-05-14 14:24:16 -07:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let s = if cx.ccx.sess.opts.save_temps || cx.ccx.sess.opts.debuginfo {
|
|
|
|
cx.ccx.names(name)
|
2012-07-18 16:18:02 -07:00
|
|
|
} else { special_idents::invalid };
|
|
|
|
let llbb: BasicBlockRef = str::as_c_str(cx.ccx.sess.str_of(s), |buf| {
|
2012-02-17 11:18:14 +01:00
|
|
|
llvm::LLVMAppendBasicBlock(cx.llfn, buf)
|
|
|
|
});
|
2012-09-12 11:15:39 -07:00
|
|
|
let bcx = mk_block(llbb, parent, move kind, is_lpad, opt_node_info, cx);
|
2012-09-21 19:37:57 -07:00
|
|
|
do option::iter(&parent) |cx| {
|
2011-09-21 12:40:27 +02:00
|
|
|
if cx.unreachable { Unreachable(bcx); }
|
2012-06-12 14:55:44 -07:00
|
|
|
};
|
2012-08-01 17:30:05 -07:00
|
|
|
return bcx;
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn simple_block_scope() -> block_kind {
|
2012-08-20 12:23:37 -07:00
|
|
|
block_scope({loop_break: None, mut cleanups: ~[],
|
|
|
|
mut cleanup_paths: ~[], mut landing_pad: None})
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-10-04 15:55:12 -07:00
|
|
|
// Use this when you're at the top block of a function or the like.
|
2012-08-20 12:23:37 -07:00
|
|
|
fn top_scope_block(fcx: fn_ctxt, opt_node_info: Option<node_info>) -> block {
|
|
|
|
return new_block(fcx, None, simple_block_scope(), false,
|
2012-07-13 22:57:48 -07:00
|
|
|
~"function top level", opt_node_info);
|
2012-01-28 20:49:21 +01:00
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn scope_block(bcx: block,
|
2012-08-20 12:23:37 -07:00
|
|
|
opt_node_info: Option<node_info>,
|
2012-07-13 22:57:48 -07:00
|
|
|
n: ~str) -> block {
|
2012-08-20 12:23:37 -07:00
|
|
|
return new_block(bcx.fcx, Some(bcx), simple_block_scope(), bcx.is_lpad,
|
2012-05-14 14:24:16 -07:00
|
|
|
n, opt_node_info);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2012-07-13 22:57:48 -07:00
|
|
|
fn loop_scope_block(bcx: block, loop_break: block, n: ~str,
|
2012-08-20 12:23:37 -07:00
|
|
|
opt_node_info: Option<node_info>) -> block {
|
|
|
|
return new_block(bcx.fcx, Some(bcx), block_scope({
|
|
|
|
loop_break: Some(loop_break),
|
2012-06-29 16:26:56 -07:00
|
|
|
mut cleanups: ~[],
|
|
|
|
mut cleanup_paths: ~[],
|
2012-08-20 12:23:37 -07:00
|
|
|
mut landing_pad: None
|
2012-07-23 16:00:19 -07:00
|
|
|
}), bcx.is_lpad, n, opt_node_info);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2012-07-23 16:00:19 -07:00
|
|
|
// Use this when creating a block for the inside of a landing pad.
|
|
|
|
fn lpad_block(bcx: block, n: ~str) -> block {
|
2012-08-20 12:23:37 -07:00
|
|
|
new_block(bcx.fcx, Some(bcx), block_non_scope, true, n, None)
|
2012-07-23 16:00:19 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2010-12-02 19:12:34 -08:00
|
|
|
// Use this when you're making a general CFG BB within a scope.
|
2012-07-13 22:57:48 -07:00
|
|
|
fn sub_block(bcx: block, n: ~str) -> block {
|
2012-08-20 12:23:37 -07:00
|
|
|
new_block(bcx.fcx, Some(bcx), block_non_scope, bcx.is_lpad, n, None)
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2012-07-23 16:00:19 -07:00
|
|
|
fn raw_block(fcx: fn_ctxt, is_lpad: bool, llbb: BasicBlockRef) -> block {
|
2012-08-20 12:23:37 -07:00
|
|
|
mk_block(llbb, None, block_non_scope, is_lpad, None, fcx)
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-27 17:58:22 -07:00
|
|
|
// trans_block_cleanups: Go through all the cleanups attached to this
|
2012-02-17 13:17:40 +01:00
|
|
|
// block and execute them.
|
2011-05-27 17:58:22 -07:00
|
|
|
//
|
2012-03-27 22:08:48 -07:00
|
|
|
// When translating a block that introduces new variables during its scope, we
|
2011-05-27 17:58:22 -07:00
|
|
|
// need to make sure those variables go out of scope when the block ends. We
|
|
|
|
// do that by running a 'cleanup' function for each variable.
|
|
|
|
// trans_block_cleanups runs all the cleanup functions for the block.
|
2012-08-23 17:39:07 -07:00
|
|
|
fn trans_block_cleanups(bcx: block, +cleanups: ~[cleanup]) -> block {
|
|
|
|
trans_block_cleanups_(bcx, cleanups, false)
|
2012-03-23 17:52:20 -07:00
|
|
|
}
|
|
|
|
|
2012-08-23 17:39:07 -07:00
|
|
|
fn trans_block_cleanups_(bcx: block,
|
|
|
|
+cleanups: ~[cleanup],
|
|
|
|
/* cleanup_cx: block, */ is_lpad: bool) ->
|
2012-02-17 13:17:40 +01:00
|
|
|
block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_block_cleanups");
|
2012-08-27 12:31:32 -07:00
|
|
|
// NB: Don't short-circuit even if this block is unreachable because
|
|
|
|
// GC-based cleanup needs to the see that the roots are live.
|
|
|
|
let no_lpads =
|
|
|
|
bcx.ccx().sess.opts.debugging_opts & session::no_landing_pads != 0;
|
|
|
|
if bcx.unreachable && !no_lpads { return bcx; }
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-09-21 18:43:30 -07:00
|
|
|
for vec::rev_each(cleanups) |cu| {
|
|
|
|
match *cu {
|
|
|
|
clean(cfn, cleanup_type) | clean_temp(_, cfn, cleanup_type) => {
|
2012-03-23 17:52:20 -07:00
|
|
|
// Some types don't need to be cleaned up during
|
|
|
|
// landing pads because they can be freed en mass later
|
|
|
|
if cleanup_type == normal_exit_and_unwind || !is_lpad {
|
|
|
|
bcx = cfn(bcx);
|
|
|
|
}
|
|
|
|
}
|
2012-08-24 21:03:51 -07:00
|
|
|
}
|
2012-09-21 18:43:30 -07:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return bcx;
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
// In the last argument, Some(block) mean jump to this block, and none means
|
2012-02-15 13:57:29 +01:00
|
|
|
// this is a landing pad and leaving should be accomplished with a resume
|
|
|
|
// instruction.
|
2012-08-20 12:23:37 -07:00
|
|
|
fn cleanup_and_leave(bcx: block, upto: Option<BasicBlockRef>,
|
|
|
|
leave: Option<BasicBlockRef>) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("cleanup_and_leave");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut cur = bcx, bcx = bcx;
|
2012-08-20 12:23:37 -07:00
|
|
|
let is_lpad = leave == None;
|
2012-03-10 20:34:17 -08:00
|
|
|
loop {
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("cleanup_and_leave: leaving %s", cur.to_str());
|
2012-05-14 20:32:29 -07:00
|
|
|
|
2012-05-18 19:02:39 -07:00
|
|
|
if bcx.sess().trace() {
|
|
|
|
trans_trace(
|
2012-08-20 12:23:37 -07:00
|
|
|
bcx, None,
|
2012-08-22 17:24:52 -07:00
|
|
|
fmt!("cleanup_and_leave(%s)", cur.to_str()));
|
2012-05-14 20:32:29 -07:00
|
|
|
}
|
|
|
|
|
2012-08-06 12:34:08 -07:00
|
|
|
match cur.kind {
|
2012-08-03 19:59:04 -07:00
|
|
|
block_scope(inf) if inf.cleanups.len() > 0u => {
|
2012-05-14 20:32:29 -07:00
|
|
|
for vec::find(inf.cleanup_paths,
|
2012-06-30 16:19:07 -07:00
|
|
|
|cp| cp.target == leave).each |cp| {
|
2012-04-06 20:01:43 +02:00
|
|
|
Br(bcx, cp.dest);
|
2012-08-01 17:30:05 -07:00
|
|
|
return;
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
2012-07-13 22:57:48 -07:00
|
|
|
let sub_cx = sub_block(bcx, ~"cleanup");
|
2012-02-15 13:57:29 +01:00
|
|
|
Br(bcx, sub_cx.llbb);
|
2012-09-26 17:33:34 -07:00
|
|
|
inf.cleanup_paths.push({target: leave, dest: sub_cx.llbb});
|
2012-08-23 17:39:07 -07:00
|
|
|
bcx = trans_block_cleanups_(sub_cx, block_cleanups(cur), is_lpad);
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
2012-08-06 12:34:08 -07:00
|
|
|
match upto {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(bb) => { if cur.llbb == bb { break; } }
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
2012-08-06 12:34:08 -07:00
|
|
|
cur = match cur.parent {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(next) => next,
|
2012-09-21 19:37:57 -07:00
|
|
|
None => { assert upto.is_none(); break; }
|
2012-02-15 13:57:29 +01:00
|
|
|
};
|
|
|
|
}
|
2012-08-06 12:34:08 -07:00
|
|
|
match leave {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(target) => Br(bcx, target),
|
2012-09-21 19:37:57 -07:00
|
|
|
None => { Resume(bcx, Load(bcx, bcx.fcx.personality.get())); }
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn cleanup_and_Br(bcx: block, upto: block,
|
2012-02-15 13:57:29 +01:00
|
|
|
target: BasicBlockRef) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("cleanup_and_Br");
|
2012-08-20 12:23:37 -07:00
|
|
|
cleanup_and_leave(bcx, Some(upto.llbb), Some(target));
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn leave_block(bcx: block, out_of: block) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("leave_block");
|
2012-07-13 22:57:48 -07:00
|
|
|
let next_cx = sub_block(block_parent(out_of), ~"next");
|
2012-02-17 13:17:40 +01:00
|
|
|
if bcx.unreachable { Unreachable(next_cx); }
|
|
|
|
cleanup_and_Br(bcx, out_of, next_cx.llbb);
|
|
|
|
next_cx
|
|
|
|
}
|
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
fn with_scope(bcx: block, opt_node_info: Option<node_info>,
|
2012-07-13 22:57:48 -07:00
|
|
|
name: ~str, f: fn(block) -> block) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("with_scope");
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
debug!("with_scope(bcx=%s, opt_node_info=%?, name=%s)",
|
|
|
|
bcx.to_str(), opt_node_info, name);
|
|
|
|
let _indenter = indenter();
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
let scope_cx = scope_block(bcx, opt_node_info, name);
|
2012-02-17 13:17:40 +01:00
|
|
|
Br(bcx, scope_cx.llbb);
|
|
|
|
leave_block(f(scope_cx), scope_cx)
|
|
|
|
}
|
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
fn with_scope_result(bcx: block, opt_node_info: Option<node_info>,
|
2012-08-28 15:54:45 -07:00
|
|
|
name: ~str, f: fn(block) -> Result)
|
|
|
|
-> Result
|
|
|
|
{
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = bcx.insn_ctxt("with_scope_result");
|
2012-05-14 14:24:16 -07:00
|
|
|
let scope_cx = scope_block(bcx, opt_node_info, name);
|
2012-02-17 13:17:40 +01:00
|
|
|
Br(bcx, scope_cx.llbb);
|
2012-08-28 15:54:45 -07:00
|
|
|
let Result {bcx, val} = f(scope_cx);
|
|
|
|
rslt(leave_block(bcx, scope_cx), val)
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
fn with_scope_datumblock(bcx: block, opt_node_info: Option<node_info>,
|
|
|
|
name: ~str, f: fn(block) -> datum::DatumBlock)
|
|
|
|
-> datum::DatumBlock
|
|
|
|
{
|
2012-09-07 18:08:21 -07:00
|
|
|
use datum::DatumBlock;
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
let _icx = bcx.insn_ctxt("with_scope_result");
|
|
|
|
let scope_cx = scope_block(bcx, opt_node_info, name);
|
|
|
|
Br(bcx, scope_cx.llbb);
|
|
|
|
let DatumBlock {bcx, datum} = f(scope_cx);
|
|
|
|
DatumBlock {bcx: leave_block(bcx, scope_cx), datum: datum}
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
|
|
|
|
2012-01-23 14:59:00 -08:00
|
|
|
fn block_locals(b: ast::blk, it: fn(@ast::local)) {
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(b.node.stmts) |s| {
|
2012-08-06 12:34:08 -07:00
|
|
|
match s.node {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::stmt_decl(d, _) => {
|
2012-08-06 12:34:08 -07:00
|
|
|
match d.node {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::decl_local(locals) => {
|
2012-09-18 21:41:37 -07:00
|
|
|
for vec::each(locals) |local| {
|
|
|
|
it(*local);
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn alloc_local(cx: block, local: @ast::local) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("alloc_local");
|
2012-02-02 12:37:17 +01:00
|
|
|
let t = node_id_type(cx, local.node.id);
|
2012-08-06 12:34:08 -07:00
|
|
|
let simple_name = match local.node.pat.node {
|
2012-08-20 12:23:37 -07:00
|
|
|
ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)),
|
|
|
|
_ => None
|
2011-10-07 11:20:51 +02:00
|
|
|
};
|
2012-03-23 14:45:47 +01:00
|
|
|
let val = alloc_ty(cx, t);
|
2012-02-22 16:57:23 +01:00
|
|
|
if cx.sess().opts.debuginfo {
|
2012-09-21 19:37:57 -07:00
|
|
|
do option::iter(&simple_name) |name| {
|
2012-09-27 17:01:28 -07:00
|
|
|
str::as_c_str(cx.ccx().sess.str_of(*name), |buf| {
|
2012-02-22 16:57:23 +01:00
|
|
|
llvm::LLVMSetValueName(val, buf)
|
2011-10-07 11:20:51 +02:00
|
|
|
});
|
2011-07-28 12:01:45 +02:00
|
|
|
}
|
2011-07-15 16:40:04 -07:00
|
|
|
}
|
2012-02-22 16:57:23 +01:00
|
|
|
cx.fcx.lllocals.insert(local.node.id, local_mem(val));
|
2012-08-01 17:30:05 -07:00
|
|
|
return cx;
|
2011-02-10 15:00:16 -08:00
|
|
|
}
|
|
|
|
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
fn with_cond(bcx: block, val: ValueRef, f: fn(block) -> block) -> block {
|
|
|
|
let _icx = bcx.insn_ctxt("with_cond");
|
|
|
|
let next_cx = base::sub_block(bcx, ~"next");
|
|
|
|
let cond_cx = base::sub_block(bcx, ~"cond");
|
|
|
|
CondBr(bcx, val, cond_cx.llbb, next_cx.llbb);
|
|
|
|
let after_cx = f(cond_cx);
|
|
|
|
if !after_cx.terminated { Br(after_cx, next_cx.llbb); }
|
|
|
|
next_cx
|
|
|
|
}
|
|
|
|
|
|
|
|
fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
|
|
|
|
n_bytes: ValueRef) {
|
|
|
|
// FIXME (Related to #1645, I think?): Provide LLVM with better
|
|
|
|
// alignment information when the alignment is statically known (it must
|
|
|
|
// be nothing more than a constant int, or LLVM complains -- not even a
|
|
|
|
// constant element of a tydesc works).
|
|
|
|
let _icx = cx.insn_ctxt("call_memmove");
|
|
|
|
let ccx = cx.ccx();
|
|
|
|
let key = match ccx.sess.targ_cfg.arch {
|
|
|
|
session::arch_x86 | session::arch_arm => ~"llvm.memmove.p0i8.p0i8.i32",
|
|
|
|
session::arch_x86_64 => ~"llvm.memmove.p0i8.p0i8.i64"
|
|
|
|
};
|
|
|
|
let memmove = ccx.intrinsics.get(key);
|
|
|
|
let src_ptr = PointerCast(cx, src, T_ptr(T_i8()));
|
|
|
|
let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8()));
|
|
|
|
let size = IntCast(cx, n_bytes, ccx.int_type);
|
|
|
|
let align = C_i32(1i32);
|
|
|
|
let volatile = C_bool(false);
|
|
|
|
Call(cx, memmove, ~[dst_ptr, src_ptr, size, align, volatile]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn memmove_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) {
|
|
|
|
let _icx = bcx.insn_ctxt("memmove_ty");
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
if ty::type_is_structural(t) {
|
|
|
|
let llsz = llsize_of(ccx, type_of::type_of(ccx, t));
|
|
|
|
call_memmove(bcx, dst, src, llsz);
|
|
|
|
} else {
|
|
|
|
Store(bcx, Load(bcx, src), dst);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) {
|
|
|
|
let _icx = cx.insn_ctxt("zero_mem");
|
|
|
|
let bcx = cx;
|
|
|
|
let ccx = cx.ccx();
|
|
|
|
let llty = type_of::type_of(ccx, t);
|
|
|
|
memzero(bcx, llptr, llty);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Always use this function instead of storing a zero constant to the memory
|
|
|
|
// in question. If you store a zero constant, LLVM will drown in vreg
|
|
|
|
// allocation for large data structures, and the generated code will be
|
|
|
|
// awful. (A telltale sign of this is large quantities of
|
|
|
|
// `mov [byte ptr foo],0` in the generated code.)
|
|
|
|
fn memzero(cx: block, llptr: ValueRef, llty: TypeRef) {
|
|
|
|
let _icx = cx.insn_ctxt("memzero");
|
|
|
|
let ccx = cx.ccx();
|
|
|
|
|
|
|
|
let intrinsic_key;
|
|
|
|
match ccx.sess.targ_cfg.arch {
|
|
|
|
session::arch_x86 | session::arch_arm => {
|
|
|
|
intrinsic_key = ~"llvm.memset.p0i8.i32";
|
|
|
|
}
|
|
|
|
session::arch_x86_64 => {
|
|
|
|
intrinsic_key = ~"llvm.memset.p0i8.i64";
|
|
|
|
}
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
2012-08-28 15:54:45 -07:00
|
|
|
|
|
|
|
let llintrinsicfn = ccx.intrinsics.get(intrinsic_key);
|
|
|
|
let llptr = PointerCast(cx, llptr, T_ptr(T_i8()));
|
|
|
|
let llzeroval = C_u8(0);
|
|
|
|
let size = IntCast(cx, shape::llsize_of(ccx, llty), ccx.int_type);
|
|
|
|
let align = C_i32(1i32);
|
|
|
|
let volatile = C_bool(false);
|
|
|
|
Call(cx, llintrinsicfn, ~[llptr, llzeroval, size, align, volatile]);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloc_ty(bcx: block, t: ty::t) -> ValueRef {
|
|
|
|
let _icx = bcx.insn_ctxt("alloc_ty");
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let llty = type_of::type_of(ccx, t);
|
|
|
|
if ty::type_has_params(t) { log(error, ty_to_str(ccx.tcx, t)); }
|
|
|
|
assert !ty::type_has_params(t);
|
|
|
|
let val = alloca(bcx, llty);
|
|
|
|
return val;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloca(cx: block, t: TypeRef) -> ValueRef {
|
|
|
|
alloca_maybe_zeroed(cx, t, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloca_zeroed(cx: block, t: TypeRef) -> ValueRef {
|
|
|
|
alloca_maybe_zeroed(cx, t, true)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn alloca_maybe_zeroed(cx: block, t: TypeRef, zero: bool) -> ValueRef {
|
|
|
|
let _icx = cx.insn_ctxt("alloca");
|
|
|
|
if cx.unreachable { return llvm::LLVMGetUndef(t); }
|
|
|
|
let initcx = base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas);
|
|
|
|
let p = Alloca(initcx, t);
|
|
|
|
if zero { memzero(initcx, p, t); }
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef {
|
|
|
|
let _icx = cx.insn_ctxt("arrayalloca");
|
|
|
|
if cx.unreachable { return llvm::LLVMGetUndef(t); }
|
|
|
|
return ArrayAlloca(
|
|
|
|
base::raw_block(cx.fcx, false, cx.fcx.llstaticallocas), t, v);
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
|
|
|
|
2012-03-12 10:05:15 +01:00
|
|
|
// Creates the standard set of basic blocks for a function
|
2011-07-27 14:19:39 +02:00
|
|
|
fn mk_standard_basic_blocks(llfn: ValueRef) ->
|
2012-03-12 10:05:15 +01:00
|
|
|
{sa: BasicBlockRef, ca: BasicBlockRef, rt: BasicBlockRef} {
|
2012-07-13 22:57:48 -07:00
|
|
|
{sa: str::as_c_str(~"static_allocas",
|
2012-06-30 16:19:07 -07:00
|
|
|
|buf| llvm::LLVMAppendBasicBlock(llfn, buf)),
|
2012-07-13 22:57:48 -07:00
|
|
|
ca: str::as_c_str(~"load_env",
|
2012-06-30 16:19:07 -07:00
|
|
|
|buf| llvm::LLVMAppendBasicBlock(llfn, buf)),
|
2012-07-13 22:57:48 -07:00
|
|
|
rt: str::as_c_str(~"return",
|
2012-06-30 16:19:07 -07:00
|
|
|
|buf| llvm::LLVMAppendBasicBlock(llfn, buf))}
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
2012-03-14 17:31:16 -07:00
|
|
|
fn new_fn_ctxt_w_id(ccx: @crate_ctxt, path: path,
|
2012-02-03 09:53:37 +01:00
|
|
|
llfndecl: ValueRef, id: ast::node_id,
|
2012-08-20 12:23:37 -07:00
|
|
|
param_substs: Option<param_substs>,
|
|
|
|
sp: Option<span>) -> fn_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llbbs = mk_standard_basic_blocks(llfndecl);
|
2012-08-01 17:30:05 -07:00
|
|
|
return @{llfn: llfndecl,
|
2012-01-18 19:29:37 +08:00
|
|
|
llenv: llvm::LLVMGetParam(llfndecl, 1u as c_uint),
|
|
|
|
llretptr: llvm::LLVMGetParam(llfndecl, 0u as c_uint),
|
2012-03-26 18:35:18 -07:00
|
|
|
mut llstaticallocas: llbbs.sa,
|
|
|
|
mut llloadenv: llbbs.ca,
|
|
|
|
mut llreturn: llbbs.rt,
|
2012-08-20 12:23:37 -07:00
|
|
|
mut llself: None,
|
|
|
|
mut personality: None,
|
|
|
|
mut loop_ret: None,
|
2012-09-19 09:41:06 -07:00
|
|
|
llargs: HashMap(),
|
|
|
|
lllocals: HashMap(),
|
|
|
|
llupvars: HashMap(),
|
2011-08-02 15:13:08 -07:00
|
|
|
id: id,
|
2012-02-02 12:37:17 +01:00
|
|
|
param_substs: param_substs,
|
2012-01-28 20:49:21 +01:00
|
|
|
span: sp,
|
2012-02-03 09:53:37 +01:00
|
|
|
path: path,
|
|
|
|
ccx: ccx};
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn new_fn_ctxt(ccx: @crate_ctxt, path: path, llfndecl: ValueRef,
|
2012-08-20 12:23:37 -07:00
|
|
|
sp: Option<span>) -> fn_ctxt {
|
|
|
|
return new_fn_ctxt_w_id(ccx, path, llfndecl, -1, None, sp);
|
2011-08-02 15:13:08 -07:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-02-08 11:47:53 -08:00
|
|
|
// NB: must keep 4 fns in sync:
|
|
|
|
//
|
2011-09-14 14:34:50 +02:00
|
|
|
// - type_of_fn
|
2011-02-08 11:47:53 -08:00
|
|
|
// - create_llargs_for_fn_args.
|
|
|
|
// - new_fn_ctxt
|
|
|
|
// - trans_args
|
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// create_llargs_for_fn_args: Creates a mapping from incoming arguments to
|
|
|
|
// allocas created for them.
|
|
|
|
//
|
|
|
|
// When we translate a function, we need to map its incoming arguments to the
|
|
|
|
// spaces that have been created for them (by code in the llallocas field of
|
|
|
|
// the function's fn_ctxt). create_llargs_for_fn_args populates the llargs
|
|
|
|
// field of the fn_ctxt with
|
2012-03-01 19:37:52 -08:00
|
|
|
fn create_llargs_for_fn_args(cx: fn_ctxt,
|
|
|
|
ty_self: self_arg,
|
2012-09-20 12:29:15 -07:00
|
|
|
args: ~[ast::arg]) -> ~[ValueRef] {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
|
2012-09-20 12:29:15 -07:00
|
|
|
|
2012-08-06 12:34:08 -07:00
|
|
|
match ty_self {
|
2012-08-03 19:59:04 -07:00
|
|
|
impl_self(tt) => {
|
2012-08-28 15:54:45 -07:00
|
|
|
cx.llself = Some(ValSelfData {
|
|
|
|
v: cx.llenv,
|
|
|
|
t: tt,
|
|
|
|
is_owned: false
|
|
|
|
});
|
2012-08-16 16:44:22 -07:00
|
|
|
}
|
|
|
|
impl_owned_self(tt) => {
|
2012-08-28 15:54:45 -07:00
|
|
|
cx.llself = Some(ValSelfData {
|
|
|
|
v: cx.llenv,
|
|
|
|
t: tt,
|
|
|
|
is_owned: true
|
|
|
|
});
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
no_self => ()
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2011-08-02 16:24:38 -07:00
|
|
|
|
2012-09-20 12:29:15 -07:00
|
|
|
// Return an array containing the ValueRefs that we get from
|
|
|
|
// llvm::LLVMGetParam for each argument.
|
|
|
|
vec::from_fn(args.len(), |i| {
|
|
|
|
let arg_n = first_real_arg + i;
|
|
|
|
llvm::LLVMGetParam(cx.llfn, arg_n as c_uint)
|
|
|
|
})
|
2010-12-09 17:38:17 -08:00
|
|
|
}
|
|
|
|
|
2012-09-20 12:29:15 -07:00
|
|
|
fn copy_args_to_allocas(fcx: fn_ctxt,
|
|
|
|
bcx: block,
|
|
|
|
args: &[ast::arg],
|
|
|
|
raw_llargs: &[ValueRef],
|
|
|
|
arg_tys: &[ty::arg]) -> block {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = fcx.insn_ctxt("copy_args_to_allocas");
|
2012-02-21 14:20:18 +01:00
|
|
|
let tcx = bcx.tcx();
|
2012-09-20 12:29:15 -07:00
|
|
|
let mut bcx = bcx;
|
2012-08-16 16:44:22 -07:00
|
|
|
|
|
|
|
match fcx.llself {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(copy slf) => {
|
2012-08-28 15:54:45 -07:00
|
|
|
// We really should do this regardless of whether self is owned, but
|
|
|
|
// it doesn't work right with default method impls yet. (FIXME: #2794)
|
2012-08-16 16:44:22 -07:00
|
|
|
if slf.is_owned {
|
|
|
|
let self_val = PointerCast(bcx, slf.v,
|
|
|
|
T_ptr(type_of(bcx.ccx(), slf.t)));
|
2012-08-28 15:54:45 -07:00
|
|
|
fcx.llself = Some(ValSelfData {v: self_val, ..slf});
|
2012-08-16 16:44:22 -07:00
|
|
|
add_clean(bcx, self_val, slf.t);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {}
|
|
|
|
}
|
|
|
|
|
2012-09-20 12:29:15 -07:00
|
|
|
for uint::range(0, arg_tys.len()) |arg_n| {
|
|
|
|
let arg_ty = &arg_tys[arg_n];
|
|
|
|
let raw_llarg = raw_llargs[arg_n];
|
|
|
|
let arg_id = args[arg_n].id;
|
|
|
|
|
|
|
|
// For certain mode/type combinations, the raw llarg values are passed
|
|
|
|
// by value. However, within the fn body itself, we want to always
|
2012-09-26 19:40:05 -07:00
|
|
|
// have all locals and arguments be by-ref so that we can cancel the
|
2012-09-20 12:29:15 -07:00
|
|
|
// cleanup and for better interaction with LLVM's debug info. So, if
|
|
|
|
// the argument would be passed by value, we store it into an alloca.
|
|
|
|
// This alloca should be optimized away by LLVM's mem-to-reg pass in
|
|
|
|
// the event it's not truly needed.
|
|
|
|
let llarg;
|
|
|
|
match ty::resolved_mode(tcx, arg_ty.mode) {
|
2012-10-05 22:07:53 -07:00
|
|
|
ast::by_ref => {
|
2012-09-20 12:29:15 -07:00
|
|
|
llarg = raw_llarg;
|
|
|
|
}
|
|
|
|
ast::by_move | ast::by_copy => {
|
|
|
|
// only by value if immediate:
|
|
|
|
if datum::appropriate_mode(arg_ty.ty).is_by_value() {
|
|
|
|
let alloc = alloc_ty(bcx, arg_ty.ty);
|
|
|
|
Store(bcx, raw_llarg, alloc);
|
|
|
|
llarg = alloc;
|
|
|
|
} else {
|
|
|
|
llarg = raw_llarg;
|
|
|
|
}
|
|
|
|
|
|
|
|
add_clean(bcx, llarg, arg_ty.ty);
|
|
|
|
}
|
|
|
|
ast::by_val => {
|
|
|
|
// always by value, also not owned, so don't add a cleanup:
|
|
|
|
let alloc = alloc_ty(bcx, arg_ty.ty);
|
|
|
|
Store(bcx, raw_llarg, alloc);
|
|
|
|
llarg = alloc;
|
2011-10-06 14:17:56 +02:00
|
|
|
}
|
2010-12-07 12:34:10 -08:00
|
|
|
}
|
2012-09-20 12:29:15 -07:00
|
|
|
|
|
|
|
fcx.llargs.insert(arg_id, local_mem(llarg));
|
|
|
|
|
2012-02-21 14:20:18 +01:00
|
|
|
if fcx.ccx.sess.opts.extra_debuginfo {
|
2012-01-27 12:55:21 +01:00
|
|
|
debuginfo::create_arg(bcx, args[arg_n], args[arg_n].ty.span);
|
2011-12-06 00:05:22 -05:00
|
|
|
}
|
2010-11-26 17:47:27 -08:00
|
|
|
}
|
2012-09-20 12:29:15 -07:00
|
|
|
|
2012-08-01 17:30:05 -07:00
|
|
|
return bcx;
|
2010-11-26 17:47:27 -08:00
|
|
|
}
|
|
|
|
|
2012-03-12 10:05:15 +01:00
|
|
|
// Ties up the llstaticallocas -> llloadenv -> lltop edges,
|
|
|
|
// and builds the return block.
|
2012-02-21 15:11:20 +01:00
|
|
|
fn finish_fn(fcx: fn_ctxt, lltop: BasicBlockRef) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = fcx.insn_ctxt("finish_fn");
|
2012-02-13 16:06:56 -08:00
|
|
|
tie_up_header_blocks(fcx, lltop);
|
2012-07-23 16:00:19 -07:00
|
|
|
let ret_cx = raw_block(fcx, false, fcx.llreturn);
|
2012-02-13 16:06:56 -08:00
|
|
|
RetVoid(ret_cx);
|
|
|
|
}
|
|
|
|
|
2012-02-21 15:11:20 +01:00
|
|
|
fn tie_up_header_blocks(fcx: fn_ctxt, lltop: BasicBlockRef) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = fcx.insn_ctxt("tie_up_header_blocks");
|
2012-07-23 16:00:19 -07:00
|
|
|
Br(raw_block(fcx, false, fcx.llstaticallocas), fcx.llloadenv);
|
|
|
|
Br(raw_block(fcx, false, fcx.llloadenv), lltop);
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2012-08-16 16:44:22 -07:00
|
|
|
enum self_arg { impl_self(ty::t), impl_owned_self(ty::t), no_self, }
|
2011-12-14 15:23:11 +01:00
|
|
|
|
2011-06-29 19:50:50 -07:00
|
|
|
// trans_closure: Builds an LLVM function out of a source function.
|
|
|
|
// If the function closes over its environment a closure will be
|
|
|
|
// returned.
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_closure(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
|
2011-12-22 17:49:54 +01:00
|
|
|
body: ast::blk, llfndecl: ValueRef,
|
2012-03-01 19:37:52 -08:00
|
|
|
ty_self: self_arg,
|
2012-08-20 12:23:37 -07:00
|
|
|
param_substs: Option<param_substs>,
|
2012-03-23 19:49:01 -07:00
|
|
|
id: ast::node_id,
|
2012-03-26 16:09:27 +02:00
|
|
|
maybe_load_env: fn(fn_ctxt),
|
|
|
|
finish: fn(block)) {
|
2012-09-12 14:48:13 -07:00
|
|
|
ccx.stats.n_closures += 1;
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_closure");
|
2011-05-24 13:47:27 -04:00
|
|
|
set_uwtable(llfndecl);
|
2010-11-26 17:47:27 -08:00
|
|
|
|
2011-06-28 18:54:05 -07:00
|
|
|
// Set up arguments to the function.
|
2012-03-23 19:49:01 -07:00
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, id, param_substs,
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(body.span));
|
2012-09-20 12:29:15 -07:00
|
|
|
let raw_llargs = create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
|
2011-08-19 14:34:45 +02:00
|
|
|
|
2012-06-26 14:27:09 -07:00
|
|
|
// Set GC for function.
|
|
|
|
if ccx.sess.opts.gc {
|
|
|
|
do str::as_c_str("generic") |strategy| {
|
|
|
|
llvm::LLVMSetGC(fcx.llfn, strategy);
|
|
|
|
}
|
2012-07-16 12:28:15 -07:00
|
|
|
ccx.uses_gc = true;
|
2012-06-26 14:27:09 -07:00
|
|
|
}
|
|
|
|
|
2011-08-19 14:34:45 +02:00
|
|
|
// Create the first basic block in the function and keep a handle on it to
|
|
|
|
// pass to finish_fn later.
|
2012-05-14 14:24:16 -07:00
|
|
|
let bcx_top = top_scope_block(fcx, body.info());
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx_top;
|
2011-08-19 14:34:45 +02:00
|
|
|
let lltop = bcx.llbb;
|
2012-02-02 12:37:17 +01:00
|
|
|
let block_ty = node_id_type(bcx, body.node.id);
|
2011-08-19 14:34:45 +02:00
|
|
|
|
2012-02-08 10:05:44 +01:00
|
|
|
let arg_tys = ty::ty_fn_args(node_id_type(bcx, id));
|
2012-09-20 12:29:15 -07:00
|
|
|
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, raw_llargs, arg_tys);
|
2011-06-28 18:54:05 -07:00
|
|
|
|
2011-09-28 15:57:38 +02:00
|
|
|
maybe_load_env(fcx);
|
2011-06-28 18:54:05 -07:00
|
|
|
|
2011-08-16 21:34:52 +02:00
|
|
|
// This call to trans_block is the place where we bridge between
|
|
|
|
// translation calls that don't have a return value (trans_crate,
|
2012-01-13 10:58:31 +01:00
|
|
|
// trans_mod, trans_item, et cetera) and those that do
|
2011-08-16 21:34:52 +02:00
|
|
|
// (trans_block, trans_expr, et cetera).
|
2012-10-08 09:00:23 -07:00
|
|
|
|
|
|
|
if !ccx.class_ctors.contains_key(id) // hack --
|
|
|
|
/* avoids the need for special cases to assign a type to
|
|
|
|
the constructor body (since it has no explicit return) */
|
|
|
|
&&
|
|
|
|
(body.node.expr.is_none() ||
|
|
|
|
ty::type_is_bot(block_ty) ||
|
|
|
|
ty::type_is_nil(block_ty)) {
|
2012-08-28 15:54:45 -07:00
|
|
|
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
|
2011-09-27 08:42:27 +02:00
|
|
|
} else {
|
2012-08-28 15:54:45 -07:00
|
|
|
bcx = controlflow::trans_block(bcx, body, expr::SaveIn(fcx.llretptr));
|
2011-09-27 08:42:27 +02:00
|
|
|
}
|
2012-03-26 16:09:27 +02:00
|
|
|
finish(bcx);
|
2012-02-15 13:57:29 +01:00
|
|
|
cleanup_and_Br(bcx, bcx_top, fcx.llreturn);
|
2011-07-15 11:38:16 -07:00
|
|
|
|
2011-06-29 17:29:24 -07:00
|
|
|
// Insert the mandatory first few basic blocks before lltop.
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2011-06-29 19:50:50 -07:00
|
|
|
}
|
|
|
|
|
2011-07-19 11:56:46 -07:00
|
|
|
// trans_fn: creates an LLVM function corresponding to a source language
|
|
|
|
// function.
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_fn(ccx: @crate_ctxt,
|
2012-03-01 19:37:52 -08:00
|
|
|
path: path,
|
|
|
|
decl: ast::fn_decl,
|
|
|
|
body: ast::blk,
|
|
|
|
llfndecl: ValueRef,
|
|
|
|
ty_self: self_arg,
|
2012-08-20 12:23:37 -07:00
|
|
|
param_substs: Option<param_substs>,
|
2012-03-23 19:49:01 -07:00
|
|
|
id: ast::node_id) {
|
2012-07-05 12:59:03 -07:00
|
|
|
let do_time = ccx.sess.trans_stats();
|
2012-02-02 12:37:17 +01:00
|
|
|
let start = if do_time { time::get_time() }
|
2012-04-02 21:41:24 -07:00
|
|
|
else { {sec: 0i64, nsec: 0i32} };
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_fn");
|
2012-09-12 14:48:13 -07:00
|
|
|
ccx.stats.n_fns += 1;
|
2012-02-02 12:37:17 +01:00
|
|
|
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
|
2012-06-30 16:19:07 -07:00
|
|
|
param_substs, id,
|
|
|
|
|fcx| {
|
|
|
|
if ccx.sess.opts.extra_debuginfo {
|
|
|
|
debuginfo::create_function(fcx);
|
|
|
|
}
|
|
|
|
},
|
|
|
|
|_bcx| { });
|
2011-10-05 11:51:41 +02:00
|
|
|
if do_time {
|
|
|
|
let end = time::get_time();
|
2012-07-18 16:18:02 -07:00
|
|
|
log_fn_time(ccx, path_str(ccx.sess, path), start, end);
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 14:24:04 -07:00
|
|
|
fn trans_enum_variant(ccx: @crate_ctxt,
|
|
|
|
enum_id: ast::node_id,
|
|
|
|
variant: ast::variant,
|
|
|
|
args: ~[ast::variant_arg],
|
|
|
|
disr: int, is_degen: bool,
|
2012-08-20 12:23:37 -07:00
|
|
|
param_substs: Option<param_substs>,
|
2012-02-09 11:17:11 +01:00
|
|
|
llfndecl: ValueRef) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_enum_variant");
|
2012-02-03 09:53:37 +01:00
|
|
|
// Translate variant arguments to function arguments.
|
2012-08-07 14:24:04 -07:00
|
|
|
let fn_args = vec::map(args, |varg|
|
2012-03-27 15:14:12 +02:00
|
|
|
{mode: ast::expl(ast::by_copy),
|
|
|
|
ty: varg.ty,
|
2012-07-18 16:18:02 -07:00
|
|
|
ident: special_idents::arg,
|
2012-06-30 16:19:07 -07:00
|
|
|
id: varg.id});
|
2012-06-29 16:26:56 -07:00
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, ~[], llfndecl, variant.node.id,
|
2012-08-20 12:23:37 -07:00
|
|
|
param_substs, None);
|
2012-09-20 12:29:15 -07:00
|
|
|
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
|
2012-08-06 12:34:08 -07:00
|
|
|
let ty_param_substs = match param_substs {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(substs) => substs.tys,
|
|
|
|
None => ~[]
|
2012-02-08 10:05:44 +01:00
|
|
|
};
|
2012-08-20 12:23:37 -07:00
|
|
|
let bcx = top_scope_block(fcx, None), lltop = bcx.llbb;
|
2012-02-08 10:05:44 +01:00
|
|
|
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
|
2012-09-20 12:29:15 -07:00
|
|
|
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
|
2011-03-03 15:52:54 -08:00
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
// Cast the enum to a type we can GEP into.
|
2012-02-03 09:53:37 +01:00
|
|
|
let llblobptr = if is_degen {
|
|
|
|
fcx.llretptr
|
|
|
|
} else {
|
|
|
|
let llenumptr =
|
|
|
|
PointerCast(bcx, fcx.llretptr, T_opaque_enum_ptr(ccx));
|
2012-08-27 12:16:37 -07:00
|
|
|
let lldiscrimptr = GEPi(bcx, llenumptr, [0u, 0u]);
|
2012-02-03 09:53:37 +01:00
|
|
|
Store(bcx, C_int(ccx, disr), lldiscrimptr);
|
2012-08-27 12:16:37 -07:00
|
|
|
GEPi(bcx, llenumptr, [0u, 1u])
|
2012-02-03 09:53:37 +01:00
|
|
|
};
|
|
|
|
let t_id = local_def(enum_id);
|
|
|
|
let v_id = local_def(variant.node.id);
|
2012-08-07 14:24:04 -07:00
|
|
|
for vec::eachi(args) |i, va| {
|
2012-03-23 14:45:47 +01:00
|
|
|
let lldestptr = GEP_enum(bcx, llblobptr, t_id, v_id,
|
|
|
|
ty_param_substs, i);
|
2012-01-19 14:24:03 -08:00
|
|
|
// If this argument to this function is a enum, it'll have come in to
|
2011-03-04 15:08:33 -08:00
|
|
|
// this function as an opaque blob due to the way that type_of()
|
|
|
|
// works. So we have to cast to the destination's view of the type.
|
2012-08-23 17:39:07 -07:00
|
|
|
let llarg = match fcx.llargs.find(va.id) {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(local_mem(x)) => x,
|
2012-08-23 17:39:07 -07:00
|
|
|
_ => fail ~"trans_enum_variant: how do we know this works?",
|
2012-02-21 14:20:18 +01:00
|
|
|
};
|
2011-08-19 15:16:48 -07:00
|
|
|
let arg_ty = arg_tys[i].ty;
|
2012-03-23 14:45:47 +01:00
|
|
|
memmove_ty(bcx, lldestptr, llarg, arg_ty);
|
2010-12-06 16:50:24 -08:00
|
|
|
}
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-01 19:03:47 -08:00
|
|
|
}
|
|
|
|
|
2012-10-08 09:00:23 -07:00
|
|
|
fn trans_class_ctor(ccx: @crate_ctxt, path: path, decl: ast::fn_decl,
|
|
|
|
body: ast::blk, llctor_decl: ValueRef,
|
|
|
|
psubsts: param_substs, ctor_id: ast::node_id,
|
|
|
|
parent_id: ast::def_id, sp: span) {
|
|
|
|
// Add ctor to the ctor map
|
|
|
|
ccx.class_ctors.insert(ctor_id, parent_id);
|
|
|
|
|
|
|
|
// Translate the ctor
|
|
|
|
|
|
|
|
// Set up the type for the result of the ctor
|
|
|
|
// kludgy -- this wouldn't be necessary if the typechecker
|
|
|
|
// special-cased constructors, then we could just look up
|
|
|
|
// the ctor's return type.
|
|
|
|
let rslt_ty = ty::mk_class(ccx.tcx, parent_id,
|
|
|
|
dummy_substs(psubsts.tys));
|
|
|
|
|
|
|
|
// Make the fn context
|
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
|
|
|
|
Some(psubsts), Some(sp));
|
|
|
|
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, decl.inputs);
|
|
|
|
let mut bcx_top = top_scope_block(fcx, body.info());
|
|
|
|
let lltop = bcx_top.llbb;
|
|
|
|
let arg_tys = ty::ty_fn_args(node_id_type(bcx_top, ctor_id));
|
|
|
|
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs,
|
|
|
|
raw_llargs, arg_tys);
|
|
|
|
|
|
|
|
// Create a temporary for `self` that we will return at the end
|
|
|
|
let selfdatum = datum::scratch_datum(bcx_top, rslt_ty, true);
|
|
|
|
|
|
|
|
// Initialize dtor flag (if any) to 1
|
|
|
|
if ty::ty_dtor(bcx_top.tcx(), parent_id).is_some() {
|
|
|
|
let flag = GEPi(bcx_top, selfdatum.val, [0, 1]);
|
|
|
|
Store(bcx_top, C_u8(1), flag);
|
|
|
|
}
|
|
|
|
|
|
|
|
// initialize fields to zero
|
|
|
|
let mut bcx = bcx_top;
|
|
|
|
|
|
|
|
// note we don't want to take *or* drop self.
|
|
|
|
fcx.llself = Some(ValSelfData {v: selfdatum.val,
|
|
|
|
t: rslt_ty,
|
|
|
|
is_owned: false});
|
|
|
|
|
|
|
|
// Translate the body of the ctor
|
|
|
|
bcx = controlflow::trans_block(bcx, body, expr::Ignore);
|
|
|
|
|
|
|
|
// Generate the return expression
|
|
|
|
bcx = selfdatum.move_to(bcx, datum::INIT, fcx.llretptr);
|
|
|
|
|
|
|
|
cleanup_and_leave(bcx, None, Some(fcx.llreturn));
|
|
|
|
Unreachable(bcx);
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
}
|
|
|
|
|
2012-05-14 14:13:32 -07:00
|
|
|
fn trans_class_dtor(ccx: @crate_ctxt, path: path,
|
2012-06-18 13:34:50 -07:00
|
|
|
body: ast::blk, dtor_id: ast::node_id,
|
2012-08-20 12:23:37 -07:00
|
|
|
psubsts: Option<param_substs>,
|
|
|
|
hash_id: Option<mono_id>, parent_id: ast::def_id)
|
2012-06-04 17:01:53 -07:00
|
|
|
-> ValueRef {
|
2012-05-22 21:44:28 -04:00
|
|
|
let tcx = ccx.tcx;
|
|
|
|
/* Look up the parent class's def_id */
|
|
|
|
let mut class_ty = ty::lookup_item_type(tcx, parent_id).ty;
|
|
|
|
/* Substitute in the class type if necessary */
|
2012-09-21 19:37:57 -07:00
|
|
|
do option::iter(&psubsts) |ss| {
|
2012-05-22 21:44:28 -04:00
|
|
|
class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The dtor takes a (null) output pointer, and a self argument,
|
|
|
|
and returns () */
|
2012-09-26 19:40:05 -07:00
|
|
|
let lldty = type_of_dtor(ccx, class_ty);
|
2012-06-18 13:34:50 -07:00
|
|
|
|
|
|
|
let s = get_dtor_symbol(ccx, path, dtor_id, psubsts);
|
|
|
|
|
2012-05-22 21:44:28 -04:00
|
|
|
/* Register the dtor as a function. It has external linkage */
|
|
|
|
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
|
|
|
|
lib::llvm::SetLinkage(lldecl, lib::llvm::ExternalLinkage);
|
|
|
|
|
|
|
|
/* If we're monomorphizing, register the monomorphized decl
|
|
|
|
for the dtor */
|
2012-09-21 19:37:57 -07:00
|
|
|
do option::iter(&hash_id) |h_id| {
|
2012-09-27 17:01:28 -07:00
|
|
|
ccx.monomorphized.insert(*h_id, lldecl);
|
2012-05-22 21:44:28 -04:00
|
|
|
}
|
2012-06-04 17:01:53 -07:00
|
|
|
/* Translate the dtor body */
|
2012-05-14 14:13:32 -07:00
|
|
|
trans_fn(ccx, path, ast_util::dtor_dec(),
|
2012-06-18 13:34:50 -07:00
|
|
|
body, lldecl, impl_self(class_ty), psubsts, dtor_id);
|
2012-05-22 21:44:28 -04:00
|
|
|
lldecl
|
2012-05-14 14:13:32 -07:00
|
|
|
}
|
|
|
|
|
2012-08-08 17:14:25 -07:00
|
|
|
fn trans_enum_def(ccx: @crate_ctxt, enum_definition: ast::enum_def,
|
2012-08-08 14:17:52 -07:00
|
|
|
id: ast::node_id, tps: ~[ast::ty_param], degen: bool,
|
|
|
|
path: @ast_map::path, vi: @~[ty::variant_info],
|
|
|
|
i: &mut uint) {
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(enum_definition.variants) |variant| {
|
2012-08-08 14:17:52 -07:00
|
|
|
let disr_val = vi[*i].disr_val;
|
|
|
|
*i += 1;
|
|
|
|
|
|
|
|
match variant.node.kind {
|
|
|
|
ast::tuple_variant_kind(args) if args.len() > 0 => {
|
|
|
|
let llfn = get_item_val(ccx, variant.node.id);
|
2012-09-18 21:41:37 -07:00
|
|
|
trans_enum_variant(ccx, id, *variant, args, disr_val,
|
2012-08-20 12:23:37 -07:00
|
|
|
degen, None, llfn);
|
2012-08-08 14:17:52 -07:00
|
|
|
}
|
|
|
|
ast::tuple_variant_kind(_) => {
|
|
|
|
// Nothing to do.
|
|
|
|
}
|
|
|
|
ast::struct_variant_kind(struct_def) => {
|
|
|
|
trans_struct_def(ccx, struct_def, tps, path,
|
|
|
|
variant.node.name, variant.node.id);
|
|
|
|
}
|
2012-08-08 17:14:25 -07:00
|
|
|
ast::enum_variant_kind(enum_definition) => {
|
|
|
|
trans_enum_def(ccx, enum_definition, id, tps, degen, path, vi,
|
|
|
|
i);
|
2012-08-08 14:17:52 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_item");
|
2012-08-23 17:39:07 -07:00
|
|
|
let path = match ccx.tcx.items.get(item.id) {
|
|
|
|
ast_map::node_item(_, p) => p,
|
|
|
|
// tjc: ?
|
|
|
|
_ => fail ~"trans_item",
|
2012-02-03 09:53:37 +01:00
|
|
|
};
|
2012-08-06 12:34:08 -07:00
|
|
|
match item.node {
|
2012-08-23 18:17:16 -07:00
|
|
|
ast::item_fn(decl, purity, tps, body) => {
|
|
|
|
if purity == ast::extern_fn {
|
2012-03-08 13:30:22 +01:00
|
|
|
let llfndecl = get_item_val(ccx, item.id);
|
2012-07-03 16:11:00 -07:00
|
|
|
foreign::trans_foreign_fn(ccx,
|
2012-06-28 13:52:13 -07:00
|
|
|
vec::append(
|
|
|
|
*path,
|
2012-06-29 16:26:56 -07:00
|
|
|
~[path_name(item.ident)]),
|
2012-06-26 16:18:37 -07:00
|
|
|
decl, body, llfndecl, item.id);
|
2012-09-26 19:40:05 -07:00
|
|
|
} else if tps.is_empty() {
|
2012-03-08 13:30:22 +01:00
|
|
|
let llfndecl = get_item_val(ccx, item.id);
|
2012-06-28 13:52:13 -07:00
|
|
|
trans_fn(ccx,
|
2012-06-29 16:26:56 -07:00
|
|
|
vec::append(*path, ~[path_name(item.ident)]),
|
2012-08-20 12:23:37 -07:00
|
|
|
decl, body, llfndecl, no_self, None, item.id);
|
2012-03-08 19:02:22 +01:00
|
|
|
} else {
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(body.node.stmts) |stmt| {
|
2012-08-06 12:34:08 -07:00
|
|
|
match stmt.node {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::stmt_decl(@{node: ast::decl_item(i), _}, _) => {
|
2012-03-08 19:02:22 +01:00
|
|
|
trans_item(ccx, *i);
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-03-08 19:02:22 +01:00
|
|
|
}
|
|
|
|
}
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-10-05 18:51:36 -07:00
|
|
|
ast::item_impl(tps, trait_refs, self_ast_ty, ms) => {
|
2012-10-05 17:49:13 -07:00
|
|
|
meth::trans_impl(ccx, *path, item.ident, ms, tps, None);
|
2012-10-05 17:31:46 -07:00
|
|
|
|
|
|
|
// Translate any methods that have provided implementations.
|
|
|
|
for trait_refs.each |trait_ref_ptr| {
|
|
|
|
let trait_def = ccx.tcx.def_map.get(trait_ref_ptr.ref_id);
|
|
|
|
|
|
|
|
// XXX: Cross-crate default methods.
|
2012-10-05 17:49:13 -07:00
|
|
|
let trait_id = def_id_of_def(trait_def);
|
|
|
|
if trait_id.crate != ast::local_crate {
|
|
|
|
loop;
|
|
|
|
}
|
|
|
|
|
2012-10-05 18:51:36 -07:00
|
|
|
// Get the self type.
|
|
|
|
let self_ty;
|
|
|
|
match ccx.tcx.ast_ty_to_ty_cache.get(self_ast_ty) {
|
|
|
|
ty::atttce_resolved(self_type) => self_ty = self_type,
|
|
|
|
ty::atttce_unresolved => {
|
|
|
|
ccx.tcx.sess.impossible_case(item.span,
|
|
|
|
~"didn't cache self ast ty");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-10-05 17:49:13 -07:00
|
|
|
match ccx.tcx.items.get(trait_id.node) {
|
2012-10-05 17:31:46 -07:00
|
|
|
ast_map::node_item(trait_item, _) => {
|
|
|
|
match trait_item.node {
|
|
|
|
ast::item_trait(tps, _, trait_methods) => {
|
|
|
|
trans_trait(ccx, tps, trait_methods, path,
|
2012-10-05 18:51:36 -07:00
|
|
|
item.ident, self_ty);
|
2012-10-05 17:31:46 -07:00
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ccx.tcx.sess.impossible_case(item.span,
|
|
|
|
~"trait item not a \
|
|
|
|
trait");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ => {
|
|
|
|
ccx.tcx.sess.impossible_case(item.span, ~"no trait item");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::item_mod(m) => {
|
2012-02-03 09:53:37 +01:00
|
|
|
trans_mod(ccx, m);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-08 17:14:25 -07:00
|
|
|
ast::item_enum(enum_definition, tps) => {
|
2012-03-08 13:30:22 +01:00
|
|
|
if tps.len() == 0u {
|
2012-08-08 17:14:25 -07:00
|
|
|
let degen = enum_definition.variants.len() == 1u;
|
2012-03-08 13:30:22 +01:00
|
|
|
let vi = ty::enum_variants(ccx.tcx, local_def(item.id));
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 0;
|
2012-08-08 17:14:25 -07:00
|
|
|
trans_enum_def(ccx, enum_definition, item.id, tps, degen, path,
|
|
|
|
vi, &mut i);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::item_const(_, expr) => consts::trans_const(ccx, expr, item.id),
|
|
|
|
ast::item_foreign_mod(foreign_mod) => {
|
2012-08-06 12:34:08 -07:00
|
|
|
let abi = match attr::foreign_abi(item.attrs) {
|
2012-08-14 16:54:13 -07:00
|
|
|
either::Right(abi_) => abi_,
|
|
|
|
either::Left(msg) => ccx.sess.span_fatal(item.span, msg)
|
2011-11-21 02:15:40 +08:00
|
|
|
};
|
2012-06-26 16:18:37 -07:00
|
|
|
foreign::trans_foreign_mod(ccx, foreign_mod, abi);
|
2011-11-10 09:14:53 -08:00
|
|
|
}
|
2012-08-07 15:34:07 -07:00
|
|
|
ast::item_class(struct_def, tps) => {
|
2012-08-07 16:46:19 -07:00
|
|
|
trans_struct_def(ccx, struct_def, tps, path, item.ident, item.id);
|
2012-03-03 17:49:23 -08:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => {/* fall through */ }
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-07 17:46:07 -07:00
|
|
|
fn trans_struct_def(ccx: @crate_ctxt, struct_def: @ast::struct_def,
|
2012-08-07 16:46:19 -07:00
|
|
|
tps: ~[ast::ty_param], path: @ast_map::path,
|
|
|
|
ident: ast::ident, id: ast::node_id) {
|
|
|
|
if tps.len() == 0u {
|
2012-10-08 09:00:23 -07:00
|
|
|
let psubsts = {tys: ty::ty_params_to_tys(ccx.tcx, tps),
|
|
|
|
vtables: None,
|
|
|
|
bounds: @~[]};
|
|
|
|
do option::iter(&struct_def.ctor) |ctor| {
|
|
|
|
trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
|
|
|
|
get_item_val(ccx, ctor.node.id), psubsts,
|
|
|
|
ctor.node.id, local_def(id), ctor.span);
|
|
|
|
}
|
2012-09-21 19:37:57 -07:00
|
|
|
do option::iter(&struct_def.dtor) |dtor| {
|
2012-08-07 16:46:19 -07:00
|
|
|
trans_class_dtor(ccx, *path, dtor.node.body,
|
2012-08-20 12:23:37 -07:00
|
|
|
dtor.node.id, None, None, local_def(id));
|
2012-08-07 16:46:19 -07:00
|
|
|
};
|
|
|
|
}
|
|
|
|
// If there are ty params, the ctor will get monomorphized
|
|
|
|
|
|
|
|
// Translate methods
|
2012-10-05 17:49:13 -07:00
|
|
|
meth::trans_impl(ccx, *path, ident, struct_def.methods, tps, None);
|
2012-08-07 16:46:19 -07:00
|
|
|
}
|
|
|
|
|
2012-08-13 16:29:40 -07:00
|
|
|
fn trans_trait(ccx: @crate_ctxt, tps: ~[ast::ty_param],
|
|
|
|
trait_methods: ~[ast::trait_method],
|
2012-10-05 17:49:13 -07:00
|
|
|
path: @ast_map::path, ident: ast::ident,
|
|
|
|
self_ty: ty::t) {
|
2012-08-13 16:29:40 -07:00
|
|
|
// Translate any methods that have provided implementations
|
|
|
|
let (_, provided_methods) = ast_util::split_trait_methods(trait_methods);
|
2012-10-05 17:49:13 -07:00
|
|
|
meth::trans_impl(ccx, *path, ident, provided_methods, tps, Some(self_ty));
|
2012-08-13 16:29:40 -07:00
|
|
|
}
|
|
|
|
|
2012-01-18 22:37:22 -08:00
|
|
|
// Translate a module. Doing this amounts to translating the items in the
|
2011-06-15 12:18:02 -07:00
|
|
|
// module; there ends up being no artifact (aside from linkage names) of
|
|
|
|
// separate modules in the compiled program. That's because modules exist
|
|
|
|
// only as a convenience for humans working with the code, to organize names
|
|
|
|
// and control visibility.
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_mod(ccx: @crate_ctxt, m: ast::_mod) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_mod");
|
2012-09-18 21:41:37 -07:00
|
|
|
for vec::each(m.items) |item| {
|
|
|
|
trans_item(ccx, **item);
|
|
|
|
}
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
fn get_pair_fn_ty(llpairty: TypeRef) -> TypeRef {
|
2011-01-07 15:12:23 -08:00
|
|
|
// Bit of a kludge: pick the fn typeref out of the pair.
|
2012-08-01 17:30:05 -07:00
|
|
|
return struct_elt(llpairty, 0u);
|
2011-01-07 15:12:23 -08:00
|
|
|
}
|
|
|
|
|
2012-03-20 15:15:57 -07:00
|
|
|
fn register_fn(ccx: @crate_ctxt, sp: span, path: path,
|
2012-03-09 10:47:40 +01:00
|
|
|
node_id: ast::node_id) -> ValueRef {
|
2012-02-02 12:37:17 +01:00
|
|
|
let t = ty::node_id_to_type(ccx.tcx, node_id);
|
2012-03-20 15:15:57 -07:00
|
|
|
register_fn_full(ccx, sp, path, node_id, t)
|
2011-06-30 12:35:19 +02:00
|
|
|
}
|
|
|
|
|
2012-03-20 15:15:57 -07:00
|
|
|
fn register_fn_full(ccx: @crate_ctxt, sp: span, path: path,
|
2012-03-09 10:47:40 +01:00
|
|
|
node_id: ast::node_id, node_type: ty::t) -> ValueRef {
|
|
|
|
let llfty = type_of_fn_from_ty(ccx, node_type);
|
2012-03-20 15:15:57 -07:00
|
|
|
register_fn_fuller(ccx, sp, path, node_id, node_type,
|
2012-03-06 11:33:25 +01:00
|
|
|
lib::llvm::CCallConv, llfty)
|
2012-02-13 16:06:56 -08:00
|
|
|
}
|
|
|
|
|
2012-03-20 15:15:57 -07:00
|
|
|
fn register_fn_fuller(ccx: @crate_ctxt, sp: span, path: path,
|
2012-02-13 16:06:56 -08:00
|
|
|
node_id: ast::node_id, node_type: ty::t,
|
2012-03-06 11:33:25 +01:00
|
|
|
cc: lib::llvm::CallConv, llfty: TypeRef) -> ValueRef {
|
2012-07-13 22:57:48 -07:00
|
|
|
let ps: ~str = mangle_exported_name(ccx, path, node_type);
|
2012-02-13 16:06:56 -08:00
|
|
|
let llfn: ValueRef = decl_fn(ccx.llmod, ps, cc, llfty);
|
2011-09-18 22:05:58 +02:00
|
|
|
ccx.item_symbols.insert(node_id, ps);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("register_fn_fuller created fn %s for item %d with path %s",
|
2012-07-18 16:18:02 -07:00
|
|
|
val_str(ccx.tn, llfn), node_id,
|
2012-08-22 17:24:52 -07:00
|
|
|
ast_map::path_to_str(path, ccx.sess.parse_sess.interner));
|
2012-02-14 15:21:53 -08:00
|
|
|
|
2012-02-03 09:53:37 +01:00
|
|
|
let is_main = is_main_name(path) && !ccx.sess.building_library;
|
2012-10-03 19:16:27 -07:00
|
|
|
if is_main { create_main_wrapper(ccx, sp, llfn); }
|
2012-03-06 11:33:25 +01:00
|
|
|
llfn
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2012-06-29 16:26:56 -07:00
|
|
|
// Create a _rust_main(args: ~[str]) function which will be called from the
|
2011-08-17 20:31:55 -07:00
|
|
|
// runtime rust_start function
|
2012-10-03 19:16:27 -07:00
|
|
|
fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef) {
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
if ccx.main_fn != None::<ValueRef> {
|
2012-07-13 22:57:48 -07:00
|
|
|
ccx.sess.span_fatal(sp, ~"multiple 'main' functions");
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2012-10-03 19:16:27 -07:00
|
|
|
let llfn = create_main(ccx, main_llfn);
|
2012-08-20 12:23:37 -07:00
|
|
|
ccx.main_fn = Some(llfn);
|
2011-10-20 13:48:10 +02:00
|
|
|
create_entry_fn(ccx, llfn);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-10-03 19:16:27 -07:00
|
|
|
fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef) -> ValueRef {
|
2012-07-14 12:19:36 -07:00
|
|
|
let unit_ty = ty::mk_estr(ccx.tcx, ty::vstore_uniq);
|
2011-09-02 16:09:41 +02:00
|
|
|
let vecarg_ty: ty::arg =
|
2012-02-02 16:50:17 -08:00
|
|
|
{mode: ast::expl(ast::by_val),
|
2012-07-14 12:19:36 -07:00
|
|
|
ty: ty::mk_evec(ccx.tcx, {ty: unit_ty, mutbl: ast::m_imm},
|
|
|
|
ty::vstore_uniq)};
|
2011-09-15 20:47:38 -07:00
|
|
|
let nt = ty::mk_nil(ccx.tcx);
|
2012-06-29 16:26:56 -07:00
|
|
|
let llfty = type_of_fn(ccx, ~[vecarg_ty], nt);
|
2012-07-13 22:57:48 -07:00
|
|
|
let llfdecl = decl_fn(ccx.llmod, ~"_rust_main",
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::CCallConv, llfty);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
let fcx = new_fn_ctxt(ccx, ~[], llfdecl, None);
|
2011-08-17 20:31:55 -07:00
|
|
|
|
2012-08-20 12:23:37 -07:00
|
|
|
let bcx = top_scope_block(fcx, None);
|
2011-08-17 20:31:55 -07:00
|
|
|
let lltop = bcx.llbb;
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-09-14 18:05:15 -07:00
|
|
|
// Call main.
|
2012-01-18 19:29:37 +08:00
|
|
|
let lloutputarg = llvm::LLVMGetParam(llfdecl, 0 as c_uint);
|
|
|
|
let llenvarg = llvm::LLVMGetParam(llfdecl, 1 as c_uint);
|
2012-06-29 16:26:56 -07:00
|
|
|
let mut args = ~[lloutputarg, llenvarg];
|
2011-09-27 18:42:06 -07:00
|
|
|
Call(bcx, main_llfn, args);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-09-14 18:05:15 -07:00
|
|
|
build_return(bcx);
|
|
|
|
finish_fn(fcx, lltop);
|
2012-08-01 17:30:05 -07:00
|
|
|
return llfdecl;
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
2011-10-20 13:48:10 +02:00
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn create_entry_fn(ccx: @crate_ctxt, rust_main: ValueRef) {
|
2012-06-07 21:38:25 -07:00
|
|
|
#[cfg(windows)]
|
2012-08-01 17:30:05 -07:00
|
|
|
fn main_name() -> ~str { return ~"WinMain@16"; }
|
2012-06-07 21:38:25 -07:00
|
|
|
#[cfg(unix)]
|
2012-08-01 17:30:05 -07:00
|
|
|
fn main_name() -> ~str { return ~"main"; }
|
2012-06-29 16:26:56 -07:00
|
|
|
let llfty = T_fn(~[ccx.int_type, ccx.int_type], ccx.int_type);
|
2011-10-20 13:48:10 +02:00
|
|
|
let llfn = decl_cdecl_fn(ccx.llmod, main_name(), llfty);
|
2012-07-13 22:57:48 -07:00
|
|
|
let llbb = str::as_c_str(~"top", |buf| {
|
2011-10-20 13:48:10 +02:00
|
|
|
llvm::LLVMAppendBasicBlock(llfn, buf)
|
|
|
|
});
|
2012-06-22 11:53:25 -07:00
|
|
|
let bld = ccx.builder.B;
|
2011-10-20 13:48:10 +02:00
|
|
|
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
|
|
|
let crate_map = ccx.crate_map;
|
2012-06-29 16:26:56 -07:00
|
|
|
let start_ty = T_fn(~[val_ty(rust_main), ccx.int_type, ccx.int_type,
|
|
|
|
val_ty(crate_map)], ccx.int_type);
|
2012-07-13 22:57:48 -07:00
|
|
|
let start = decl_cdecl_fn(ccx.llmod, ~"rust_start", start_ty);
|
2012-04-09 14:38:53 +08:00
|
|
|
|
2012-06-29 16:26:56 -07:00
|
|
|
let args = ~[rust_main, llvm::LLVMGetParam(llfn, 0 as c_uint),
|
|
|
|
llvm::LLVMGetParam(llfn, 1 as c_uint), crate_map];
|
2011-10-20 13:48:10 +02:00
|
|
|
let result = unsafe {
|
2012-09-12 17:45:23 -07:00
|
|
|
llvm::LLVMBuildCall(bld, start, vec::raw::to_ptr(args),
|
2012-02-14 09:10:47 +01:00
|
|
|
args.len() as c_uint, noname())
|
2011-10-20 13:48:10 +02:00
|
|
|
};
|
|
|
|
llvm::LLVMBuildRet(bld, result);
|
|
|
|
}
|
2011-02-28 17:33:46 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn fill_fn_pair(bcx: block, pair: ValueRef, llfn: ValueRef,
|
2011-09-28 15:57:38 +02:00
|
|
|
llenvptr: ValueRef) {
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-08-27 12:16:37 -07:00
|
|
|
let code_cell = GEPi(bcx, pair, [0u, abi::fn_field_code]);
|
2011-09-28 15:57:38 +02:00
|
|
|
Store(bcx, llfn, code_cell);
|
2012-08-27 12:16:37 -07:00
|
|
|
let env_cell = GEPi(bcx, pair, [0u, abi::fn_field_box]);
|
2012-02-01 18:52:08 -08:00
|
|
|
let llenvblobptr = PointerCast(bcx, llenvptr, T_opaque_box_ptr(ccx));
|
2011-09-28 15:57:38 +02:00
|
|
|
Store(bcx, llenvblobptr, env_cell);
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn item_path(ccx: @crate_ctxt, i: @ast::item) -> path {
|
2012-06-28 13:52:13 -07:00
|
|
|
vec::append(
|
2012-08-23 17:39:07 -07:00
|
|
|
*match ccx.tcx.items.get(i.id) {
|
|
|
|
ast_map::node_item(_, p) => p,
|
|
|
|
// separate map for paths?
|
|
|
|
_ => fail ~"item_path"
|
2012-06-28 13:52:13 -07:00
|
|
|
},
|
2012-06-29 16:26:56 -07:00
|
|
|
~[path_name(i.ident)])
|
2012-02-03 09:53:37 +01:00
|
|
|
}
|
|
|
|
|
2012-06-18 13:34:50 -07:00
|
|
|
/* If there's already a symbol for the dtor with <id> and substs <substs>,
|
|
|
|
return it; otherwise, create one and register it, returning it as well */
|
|
|
|
fn get_dtor_symbol(ccx: @crate_ctxt, path: path, id: ast::node_id,
|
2012-08-20 12:23:37 -07:00
|
|
|
substs: Option<param_substs>) -> ~str {
|
2012-06-18 13:34:50 -07:00
|
|
|
let t = ty::node_id_to_type(ccx.tcx, id);
|
2012-08-06 12:34:08 -07:00
|
|
|
match ccx.item_symbols.find(id) {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(s) => s,
|
2012-09-21 19:37:57 -07:00
|
|
|
None if substs.is_none() => {
|
2012-06-28 13:52:13 -07:00
|
|
|
let s = mangle_exported_name(
|
|
|
|
ccx,
|
2012-07-18 16:18:02 -07:00
|
|
|
vec::append(path, ~[path_name(ccx.names(~"dtor"))]),
|
2012-06-28 13:52:13 -07:00
|
|
|
t);
|
2012-06-18 13:34:50 -07:00
|
|
|
ccx.item_symbols.insert(id, s);
|
|
|
|
s
|
|
|
|
}
|
2012-08-20 12:23:37 -07:00
|
|
|
None => {
|
2012-06-18 13:34:50 -07:00
|
|
|
// Monomorphizing, so just make a symbol, don't add
|
|
|
|
// this to item_symbols
|
2012-08-06 12:34:08 -07:00
|
|
|
match substs {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(ss) => {
|
2012-06-18 13:34:50 -07:00
|
|
|
let mono_ty = ty::subst_tps(ccx.tcx, ss.tys, t);
|
2012-06-28 13:52:13 -07:00
|
|
|
mangle_exported_name(
|
|
|
|
ccx,
|
|
|
|
vec::append(path,
|
2012-07-18 16:18:02 -07:00
|
|
|
~[path_name(ccx.names(~"dtor"))]),
|
2012-06-28 13:52:13 -07:00
|
|
|
mono_ty)
|
2012-06-18 13:34:50 -07:00
|
|
|
}
|
2012-08-20 12:23:37 -07:00
|
|
|
None => {
|
2012-08-22 17:24:52 -07:00
|
|
|
ccx.sess.bug(fmt!("get_dtor_symbol: not monomorphizing and \
|
|
|
|
couldn't find a symbol for dtor %?", path));
|
2012-06-18 13:34:50 -07:00
|
|
|
}
|
|
|
|
}
|
2012-06-04 17:01:53 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("get_item_val(id=`%?`)", id);
|
2012-05-22 21:44:28 -04:00
|
|
|
let tcx = ccx.tcx;
|
2012-08-06 12:34:08 -07:00
|
|
|
match ccx.item_vals.find(id) {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(v) => v,
|
|
|
|
None => {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut exprt = false;
|
2012-08-10 17:39:10 -07:00
|
|
|
let val = match ccx.tcx.items.get(id) {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast_map::node_item(i, pth) => {
|
2012-06-29 16:26:56 -07:00
|
|
|
let my_path = vec::append(*pth, ~[path_name(i.ident)]);
|
2012-08-23 17:39:07 -07:00
|
|
|
match i.node {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::item_const(_, _) => {
|
2012-03-07 12:21:08 +01:00
|
|
|
let typ = ty::node_id_to_type(ccx.tcx, i.id);
|
2012-04-07 17:00:11 -07:00
|
|
|
let s = mangle_exported_name(ccx, my_path, typ);
|
2012-06-30 16:19:07 -07:00
|
|
|
let g = str::as_c_str(s, |buf| {
|
2012-03-07 12:21:08 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, typ), buf)
|
|
|
|
});
|
|
|
|
ccx.item_symbols.insert(i.id, s);
|
|
|
|
g
|
|
|
|
}
|
2012-08-26 09:58:45 -07:00
|
|
|
ast::item_fn(_, purity, _, _) => {
|
2012-08-23 18:17:16 -07:00
|
|
|
let llfn = if purity != ast::extern_fn {
|
2012-03-20 15:15:57 -07:00
|
|
|
register_fn(ccx, i.span, my_path, i.id)
|
2012-03-07 12:21:08 +01:00
|
|
|
} else {
|
2012-07-03 16:11:00 -07:00
|
|
|
foreign::register_foreign_fn(ccx, i.span, my_path, i.id)
|
2012-03-07 12:21:08 +01:00
|
|
|
};
|
|
|
|
set_inline_hint_if_appr(i.attrs, llfn);
|
|
|
|
llfn
|
|
|
|
}
|
2012-08-23 17:39:07 -07:00
|
|
|
_ => fail ~"get_item_val: weird result in table"
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
2012-08-10 17:39:10 -07:00
|
|
|
ast_map::node_trait_method(trait_method, _, pth) => {
|
2012-08-22 17:24:52 -07:00
|
|
|
debug!("get_item_val(): processing a node_trait_method");
|
2012-08-10 17:39:10 -07:00
|
|
|
match *trait_method {
|
|
|
|
ast::required(_) => {
|
|
|
|
ccx.sess.bug(~"unexpected variant: required trait method in \
|
|
|
|
get_item_val()");
|
|
|
|
}
|
|
|
|
ast::provided(m) => {
|
|
|
|
exprt = true;
|
2012-08-21 19:51:43 -07:00
|
|
|
register_method(ccx, id, pth, m)
|
2012-08-10 17:39:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-08-13 16:29:40 -07:00
|
|
|
ast_map::node_method(m, _, pth) => {
|
2012-03-20 13:19:33 +01:00
|
|
|
exprt = true;
|
2012-08-21 19:51:43 -07:00
|
|
|
register_method(ccx, id, pth, m)
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
ast_map::node_foreign_item(ni, _, pth) => {
|
2012-03-20 13:19:33 +01:00
|
|
|
exprt = true;
|
2012-08-25 15:09:33 -07:00
|
|
|
match ni.node {
|
|
|
|
ast::foreign_item_fn(*) => {
|
|
|
|
register_fn(ccx, ni.span,
|
|
|
|
vec::append(*pth, ~[path_name(ni.ident)]),
|
|
|
|
ni.id)
|
|
|
|
}
|
|
|
|
ast::foreign_item_const(*) => {
|
|
|
|
let typ = ty::node_id_to_type(ccx.tcx, ni.id);
|
|
|
|
let ident = ccx.sess.parse_sess.interner.get(ni.ident);
|
|
|
|
let g = do str::as_c_str(*ident) |buf| {
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, type_of(ccx, typ), buf)
|
|
|
|
};
|
|
|
|
g
|
|
|
|
}
|
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
2012-10-08 09:00:23 -07:00
|
|
|
ast_map::node_ctor(nm, _, ctor, _, pt) => {
|
|
|
|
let my_path = vec::append(*pt, ~[path_name(nm)]);
|
|
|
|
register_fn(ccx, ctor.span, my_path, ctor.node.id)
|
|
|
|
}
|
2012-08-24 14:04:38 -07:00
|
|
|
ast_map::node_dtor(_, dt, parent_id, pt) => {
|
2012-05-22 21:44:28 -04:00
|
|
|
/*
|
|
|
|
Don't just call register_fn, since we don't want to add
|
|
|
|
the implicit self argument automatically (we want to make sure
|
|
|
|
it has the right type)
|
|
|
|
*/
|
|
|
|
// Want parent_id and not id, because id is the dtor's type
|
|
|
|
let class_ty = ty::lookup_item_type(tcx, parent_id).ty;
|
|
|
|
// This code shouldn't be reached if the class is generic
|
|
|
|
assert !ty::type_has_params(class_ty);
|
2012-06-29 16:26:56 -07:00
|
|
|
let lldty = T_fn(~[T_ptr(type_of(ccx, ty::mk_nil(tcx))),
|
|
|
|
T_ptr(type_of(ccx, class_ty))],
|
2012-05-22 21:44:28 -04:00
|
|
|
llvm::LLVMVoidType());
|
2012-08-20 12:23:37 -07:00
|
|
|
let s = get_dtor_symbol(ccx, *pt, dt.node.id, None);
|
2012-06-04 17:01:53 -07:00
|
|
|
|
2012-05-22 21:44:28 -04:00
|
|
|
/* Make the declaration for the dtor */
|
|
|
|
let llfn = decl_internal_cdecl_fn(ccx.llmod, s, lldty);
|
|
|
|
lib::llvm::SetLinkage(llfn, lib::llvm::ExternalLinkage);
|
|
|
|
llfn
|
2012-05-14 14:13:32 -07:00
|
|
|
}
|
|
|
|
|
2012-08-03 19:59:04 -07:00
|
|
|
ast_map::node_variant(v, enm, pth) => {
|
2012-08-07 14:24:04 -07:00
|
|
|
let llfn;
|
|
|
|
match v.node.kind {
|
|
|
|
ast::tuple_variant_kind(args) => {
|
|
|
|
assert args.len() != 0u;
|
|
|
|
let pth = vec::append(*pth,
|
|
|
|
~[path_name(enm.ident),
|
2012-08-13 16:29:40 -07:00
|
|
|
path_name(v.node.name)]);
|
2012-08-23 17:39:07 -07:00
|
|
|
llfn = match enm.node {
|
2012-08-07 14:24:04 -07:00
|
|
|
ast::item_enum(_, _) => {
|
|
|
|
register_fn(ccx, v.span, pth, id)
|
|
|
|
}
|
2012-08-23 17:39:07 -07:00
|
|
|
_ => fail ~"node_variant, shouldn't happen"
|
2012-08-07 14:24:04 -07:00
|
|
|
};
|
|
|
|
}
|
2012-08-07 18:54:44 -07:00
|
|
|
ast::struct_variant_kind(_) => {
|
2012-08-08 14:17:52 -07:00
|
|
|
fail ~"struct variant kind unexpected in get_item_val"
|
|
|
|
}
|
|
|
|
ast::enum_variant_kind(_) => {
|
|
|
|
fail ~"enum variant kind unexpected in get_item_val"
|
2012-08-07 14:24:04 -07:00
|
|
|
}
|
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
set_inline_hint(llfn);
|
|
|
|
llfn
|
|
|
|
}
|
2012-08-10 17:39:10 -07:00
|
|
|
_ => {
|
|
|
|
ccx.sess.bug(~"get_item_val(): unexpected variant");
|
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
};
|
2012-03-20 13:19:33 +01:00
|
|
|
if !(exprt || ccx.reachable.contains_key(id)) {
|
|
|
|
lib::llvm::SetLinkage(val, lib::llvm::InternalLinkage);
|
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
ccx.item_vals.insert(id, val);
|
|
|
|
val
|
2012-03-03 17:49:23 -08:00
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-08-21 19:51:43 -07:00
|
|
|
fn register_method(ccx: @crate_ctxt, id: ast::node_id, pth: @ast_map::path,
|
2012-08-13 16:29:40 -07:00
|
|
|
m: @ast::method) -> ValueRef {
|
|
|
|
let mty = ty::node_id_to_type(ccx.tcx, id);
|
2012-07-18 16:18:02 -07:00
|
|
|
let pth = vec::append(*pth, ~[path_name(ccx.names(~"meth")),
|
2012-08-13 16:29:40 -07:00
|
|
|
path_name(m.ident)]);
|
|
|
|
let llfn = register_fn_full(ccx, m.span, pth, id, mty);
|
|
|
|
set_inline_hint_if_appr(m.attrs, llfn);
|
|
|
|
llfn
|
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// The constant translation pass.
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_constant(ccx: @crate_ctxt, it: @ast::item) {
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_constant");
|
2012-08-06 12:34:08 -07:00
|
|
|
match it.node {
|
2012-08-08 17:14:25 -07:00
|
|
|
ast::item_enum(enum_definition, _) => {
|
2012-01-25 14:34:31 +01:00
|
|
|
let vi = ty::enum_variants(ccx.tcx, {crate: ast::local_crate,
|
2012-02-03 09:53:37 +01:00
|
|
|
node: it.id});
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 0;
|
|
|
|
let path = item_path(ccx, it);
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(enum_definition.variants) |variant| {
|
2012-06-29 16:26:56 -07:00
|
|
|
let p = vec::append(path, ~[path_name(variant.node.name),
|
2012-07-18 16:18:02 -07:00
|
|
|
path_name(special_idents::descrim)]);
|
2012-04-07 17:00:11 -07:00
|
|
|
let s = mangle_exported_name(ccx, p, ty::mk_int(ccx.tcx));
|
2012-01-16 02:36:47 -07:00
|
|
|
let disr_val = vi[i].disr_val;
|
2012-03-20 14:21:02 -07:00
|
|
|
note_unique_llvm_symbol(ccx, s);
|
2012-06-30 16:19:07 -07:00
|
|
|
let discrim_gvar = str::as_c_str(s, |buf| {
|
2012-01-02 12:58:31 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
|
|
|
});
|
2012-01-10 14:50:40 -07:00
|
|
|
llvm::LLVMSetInitializer(discrim_gvar, C_int(ccx, disr_val));
|
2011-09-06 22:44:16 -07:00
|
|
|
llvm::LLVMSetGlobalConstant(discrim_gvar, True);
|
2011-10-20 15:26:26 -07:00
|
|
|
ccx.discrims.insert(
|
2012-02-03 09:53:37 +01:00
|
|
|
local_def(variant.node.id), discrim_gvar);
|
2011-08-26 17:14:13 -07:00
|
|
|
ccx.discrim_symbols.insert(variant.node.id, s);
|
2012-01-16 02:36:47 -07:00
|
|
|
i += 1;
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_constants(ccx: @crate_ctxt, crate: @ast::crate) {
|
2012-02-03 09:53:37 +01:00
|
|
|
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
|
2012-09-04 13:29:32 -07:00
|
|
|
visit_item: |a| trans_constant(ccx, a),
|
2012-08-28 15:54:45 -07:00
|
|
|
..*visit::default_simple_visitor()
|
2012-02-03 09:53:37 +01:00
|
|
|
}));
|
2010-12-02 19:30:06 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn vp2i(cx: block, v: ValueRef) -> ValueRef {
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-08-01 17:30:05 -07:00
|
|
|
return PtrToInt(cx, v, ccx.int_type);
|
2011-03-02 16:42:09 -08:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn p2i(ccx: @crate_ctxt, v: ValueRef) -> ValueRef {
|
2012-08-01 17:30:05 -07:00
|
|
|
return llvm::LLVMConstPtrToInt(v, ccx.int_type);
|
2011-10-14 17:00:17 -07:00
|
|
|
}
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2012-09-10 15:38:28 -07:00
|
|
|
fn declare_intrinsics(llmod: ModuleRef) -> HashMap<~str, ValueRef> {
|
2012-06-29 16:26:56 -07:00
|
|
|
let T_memmove32_args: ~[TypeRef] =
|
|
|
|
~[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
|
|
|
|
let T_memmove64_args: ~[TypeRef] =
|
|
|
|
~[T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
|
|
|
|
let T_memset32_args: ~[TypeRef] =
|
|
|
|
~[T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
|
|
|
|
let T_memset64_args: ~[TypeRef] =
|
|
|
|
~[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
|
|
|
|
let T_trap_args: ~[TypeRef] = ~[];
|
|
|
|
let T_frameaddress_args: ~[TypeRef] = ~[T_i32()];
|
2011-08-17 19:11:01 -07:00
|
|
|
let gcroot =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.gcroot",
|
2012-06-29 16:26:56 -07:00
|
|
|
T_fn(~[T_ptr(T_ptr(T_i8())), T_ptr(T_i8())],
|
2012-06-25 20:00:46 -07:00
|
|
|
T_void()));
|
2011-08-10 17:59:33 -07:00
|
|
|
let gcread =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.gcread",
|
2012-06-29 16:26:56 -07:00
|
|
|
T_fn(~[T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))],
|
2012-06-25 20:00:46 -07:00
|
|
|
T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memmove32 =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i32",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memmove32_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memmove64 =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.memmove.p0i8.p0i8.i64",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memmove64_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memset32 =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.memset.p0i8.i32",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memset32_args, T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memset64 =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.memset.p0i8.i64",
|
2011-06-15 11:19:50 -07:00
|
|
|
T_fn(T_memset64_args, T_void()));
|
2012-07-13 22:57:48 -07:00
|
|
|
let trap = decl_cdecl_fn(llmod, ~"llvm.trap", T_fn(T_trap_args,
|
2012-06-25 20:00:46 -07:00
|
|
|
T_void()));
|
2012-07-13 22:57:48 -07:00
|
|
|
let frameaddress = decl_cdecl_fn(llmod, ~"llvm.frameaddress",
|
2012-06-05 18:41:18 -07:00
|
|
|
T_fn(T_frameaddress_args,
|
|
|
|
T_ptr(T_i8())));
|
2012-09-19 09:41:06 -07:00
|
|
|
let intrinsics = HashMap();
|
2012-07-13 22:57:48 -07:00
|
|
|
intrinsics.insert(~"llvm.gcroot", gcroot);
|
|
|
|
intrinsics.insert(~"llvm.gcread", gcread);
|
|
|
|
intrinsics.insert(~"llvm.memmove.p0i8.p0i8.i32", memmove32);
|
|
|
|
intrinsics.insert(~"llvm.memmove.p0i8.p0i8.i64", memmove64);
|
|
|
|
intrinsics.insert(~"llvm.memset.p0i8.i32", memset32);
|
|
|
|
intrinsics.insert(~"llvm.memset.p0i8.i64", memset64);
|
|
|
|
intrinsics.insert(~"llvm.trap", trap);
|
|
|
|
intrinsics.insert(~"llvm.frameaddress", frameaddress);
|
2012-08-01 17:30:05 -07:00
|
|
|
return intrinsics;
|
2010-11-14 11:21:49 -08:00
|
|
|
}
|
|
|
|
|
2011-11-15 21:11:22 -05:00
|
|
|
fn declare_dbg_intrinsics(llmod: ModuleRef,
|
2012-09-10 15:38:28 -07:00
|
|
|
intrinsics: HashMap<~str, ValueRef>) {
|
2011-11-15 21:11:22 -05:00
|
|
|
let declare =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.dbg.declare",
|
2012-06-29 16:26:56 -07:00
|
|
|
T_fn(~[T_metadata(), T_metadata()], T_void()));
|
2011-11-15 21:11:22 -05:00
|
|
|
let value =
|
2012-07-13 22:57:48 -07:00
|
|
|
decl_cdecl_fn(llmod, ~"llvm.dbg.value",
|
2012-06-29 16:26:56 -07:00
|
|
|
T_fn(~[T_metadata(), T_i64(), T_metadata()],
|
2012-06-25 20:00:46 -07:00
|
|
|
T_void()));
|
2012-07-13 22:57:48 -07:00
|
|
|
intrinsics.insert(~"llvm.dbg.declare", declare);
|
|
|
|
intrinsics.insert(~"llvm.dbg.value", value);
|
2011-11-15 21:11:22 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trap(bcx: block) {
|
2012-06-29 16:26:56 -07:00
|
|
|
let v: ~[ValueRef] = ~[];
|
2012-08-06 12:34:08 -07:00
|
|
|
match bcx.ccx().intrinsics.find(~"llvm.trap") {
|
2012-08-20 12:23:37 -07:00
|
|
|
Some(x) => { Call(bcx, x, v); },
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => bcx.sess().bug(~"unbound llvm.trap in trap")
|
2011-07-05 19:57:34 -07:00
|
|
|
}
|
2011-02-02 15:23:49 -08:00
|
|
|
}
|
2010-12-06 17:17:49 -08:00
|
|
|
|
2012-07-10 15:52:05 -07:00
|
|
|
fn push_rtcall(ccx: @crate_ctxt, name: ~str, did: ast::def_id) {
|
2012-10-03 18:14:53 -07:00
|
|
|
match ccx.rtcalls.find(name) {
|
|
|
|
Some(existing_did) if did != existing_did => {
|
|
|
|
ccx.sess.fatal(fmt!("multiple definitions for runtime call %s",
|
|
|
|
name));
|
|
|
|
}
|
|
|
|
Some(_) | None => {
|
|
|
|
ccx.rtcalls.insert(name, did);
|
|
|
|
}
|
2012-07-10 15:52:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gather_local_rtcalls(ccx: @crate_ctxt, crate: @ast::crate) {
|
|
|
|
visit::visit_crate(*crate, (), visit::mk_simple_visitor(@{
|
2012-08-06 12:34:08 -07:00
|
|
|
visit_item: |item| match item.node {
|
2012-09-18 21:41:37 -07:00
|
|
|
ast::item_fn(*) => {
|
|
|
|
let attr_metas = attr::attr_metas(
|
|
|
|
attr::find_attrs_by_name(item.attrs, ~"rt"));
|
|
|
|
for vec::each(attr_metas) |attr_meta| {
|
2012-09-20 18:15:39 -07:00
|
|
|
match attr::get_meta_item_list(*attr_meta) {
|
2012-09-18 21:41:37 -07:00
|
|
|
Some(list) => {
|
|
|
|
let head = vec::head(list);
|
2012-09-20 18:15:39 -07:00
|
|
|
let name = attr::get_meta_item_name(head);
|
2012-09-18 21:41:37 -07:00
|
|
|
push_rtcall(ccx, name, {crate: ast::local_crate,
|
|
|
|
node: item.id});
|
|
|
|
}
|
|
|
|
None => ()
|
|
|
|
}
|
2012-07-10 15:52:05 -07:00
|
|
|
}
|
|
|
|
}
|
2012-09-18 21:41:37 -07:00
|
|
|
_ => ()
|
2012-09-04 13:29:32 -07:00
|
|
|
},
|
2012-08-28 15:54:45 -07:00
|
|
|
..*visit::default_simple_visitor()
|
2012-07-10 15:52:05 -07:00
|
|
|
}));
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gather_external_rtcalls(ccx: @crate_ctxt) {
|
|
|
|
do cstore::iter_crate_data(ccx.sess.cstore) |_cnum, cmeta| {
|
2012-07-18 16:18:02 -07:00
|
|
|
do decoder::each_path(ccx.sess.intr(), cmeta) |path| {
|
2012-07-10 15:52:05 -07:00
|
|
|
let pathname = path.path_string;
|
2012-08-06 12:34:08 -07:00
|
|
|
match path.def_like {
|
2012-08-03 19:59:04 -07:00
|
|
|
decoder::dl_def(d) => {
|
2012-08-06 12:34:08 -07:00
|
|
|
match d {
|
2012-08-03 19:59:04 -07:00
|
|
|
ast::def_fn(did, _) => {
|
2012-07-10 15:52:05 -07:00
|
|
|
// FIXME (#2861): This should really iterate attributes
|
|
|
|
// like gather_local_rtcalls, but we'll need to
|
|
|
|
// export attributes in metadata/encoder before we can do
|
|
|
|
// that.
|
2012-08-03 11:22:35 -07:00
|
|
|
let sentinel = ~"rt::rt_";
|
2012-07-10 15:52:05 -07:00
|
|
|
let slen = str::len(sentinel);
|
|
|
|
if str::starts_with(pathname, sentinel) {
|
|
|
|
let name = str::substr(pathname,
|
|
|
|
slen, str::len(pathname)-slen);
|
|
|
|
push_rtcall(ccx, name, did);
|
|
|
|
}
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-07-10 15:52:05 -07:00
|
|
|
}
|
|
|
|
}
|
2012-08-03 19:59:04 -07:00
|
|
|
_ => ()
|
2012-07-10 15:52:05 -07:00
|
|
|
}
|
|
|
|
true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn gather_rtcalls(ccx: @crate_ctxt, crate: @ast::crate) {
|
|
|
|
gather_local_rtcalls(ccx, crate);
|
|
|
|
gather_external_rtcalls(ccx);
|
|
|
|
|
|
|
|
// FIXME (#2861): Check for other rtcalls too, once they are
|
|
|
|
// supported. Also probably want to check type signature so we don't crash
|
|
|
|
// in some obscure place in LLVM if the user provides the wrong signature
|
|
|
|
// for an rtcall.
|
2012-07-17 10:48:19 -07:00
|
|
|
let expected_rtcalls =
|
2012-09-12 11:51:44 -07:00
|
|
|
~[~"exchange_free", ~"exchange_malloc", ~"fail_", ~"free", ~"malloc"];
|
2012-09-18 21:41:13 -07:00
|
|
|
for vec::each(expected_rtcalls) |name| {
|
2012-09-18 21:41:37 -07:00
|
|
|
if !ccx.rtcalls.contains_key(*name) {
|
|
|
|
fail fmt!("no definition for runtime call %s", *name);
|
2012-07-17 10:48:19 -07:00
|
|
|
}
|
2012-07-10 15:52:05 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-07-16 12:28:15 -07:00
|
|
|
fn decl_gc_metadata(ccx: @crate_ctxt, llmod_id: ~str) {
|
|
|
|
if !ccx.sess.opts.gc || !ccx.uses_gc {
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
let gc_metadata_name = ~"_gc_module_metadata_" + llmod_id;
|
|
|
|
let gc_metadata = do str::as_c_str(gc_metadata_name) |buf| {
|
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf)
|
|
|
|
};
|
|
|
|
llvm::LLVMSetGlobalConstant(gc_metadata, True);
|
|
|
|
lib::llvm::SetLinkage(gc_metadata, lib::llvm::ExternalLinkage);
|
|
|
|
ccx.module_data.insert(~"_gc_module_metadata", gc_metadata);
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn create_module_map(ccx: @crate_ctxt) -> ValueRef {
|
2012-06-29 16:26:56 -07:00
|
|
|
let elttype = T_struct(~[ccx.int_type, ccx.int_type]);
|
2011-07-27 14:19:39 +02:00
|
|
|
let maptype = T_array(elttype, ccx.module_data.size() + 1u);
|
2012-07-13 22:57:48 -07:00
|
|
|
let map = str::as_c_str(~"_rust_mod_map", |buf| {
|
2012-02-01 11:04:56 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, maptype, buf)
|
|
|
|
});
|
|
|
|
lib::llvm::SetLinkage(map, lib::llvm::InternalLinkage);
|
2012-06-29 16:26:56 -07:00
|
|
|
let mut elts: ~[ValueRef] = ~[];
|
2012-06-30 16:19:07 -07:00
|
|
|
for ccx.module_data.each |key, val| {
|
2012-06-29 16:26:56 -07:00
|
|
|
let elt = C_struct(~[p2i(ccx, C_cstr(ccx, key)),
|
|
|
|
p2i(ccx, val)]);
|
2012-09-26 17:33:34 -07:00
|
|
|
elts.push(elt);
|
2012-06-30 16:19:07 -07:00
|
|
|
}
|
2012-06-29 16:26:56 -07:00
|
|
|
let term = C_struct(~[C_int(ccx, 0), C_int(ccx, 0)]);
|
2012-09-26 17:33:34 -07:00
|
|
|
elts.push(term);
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(map, C_array(elttype, elts));
|
2012-08-01 17:30:05 -07:00
|
|
|
return map;
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-05-17 16:17:11 -07:00
|
|
|
fn decl_crate_map(sess: session::session, mapmeta: link_meta,
|
2011-10-20 13:48:10 +02:00
|
|
|
llmod: ModuleRef) -> ValueRef {
|
2012-01-12 17:59:49 +01:00
|
|
|
let targ_cfg = sess.targ_cfg;
|
2011-10-25 13:13:55 -07:00
|
|
|
let int_type = T_int(targ_cfg);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut n_subcrates = 1;
|
2012-01-12 17:59:49 +01:00
|
|
|
let cstore = sess.cstore;
|
2011-10-20 13:48:10 +02:00
|
|
|
while cstore::have_crate_data(cstore, n_subcrates) { n_subcrates += 1; }
|
2012-04-06 18:45:49 +08:00
|
|
|
let mapname = if sess.building_library {
|
2012-07-18 16:18:02 -07:00
|
|
|
mapmeta.name + ~"_" + mapmeta.vers + ~"_" + mapmeta.extras_hash
|
2012-07-13 22:57:48 -07:00
|
|
|
} else { ~"toplevel" };
|
|
|
|
let sym_name = ~"_rust_crate_map_" + mapname;
|
2011-10-25 13:13:55 -07:00
|
|
|
let arrtype = T_array(int_type, n_subcrates as uint);
|
2012-09-21 11:42:47 -07:00
|
|
|
let maptype = T_struct(~[T_i32(), T_ptr(T_i8()), int_type, arrtype]);
|
2012-06-30 16:19:07 -07:00
|
|
|
let map = str::as_c_str(sym_name, |buf| {
|
2011-10-20 13:48:10 +02:00
|
|
|
llvm::LLVMAddGlobal(llmod, maptype, buf)
|
|
|
|
});
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(map, lib::llvm::ExternalLinkage);
|
2012-08-01 17:30:05 -07:00
|
|
|
return map;
|
2011-10-20 13:48:10 +02:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn fill_crate_map(ccx: @crate_ctxt, map: ValueRef) {
|
2012-06-29 16:26:56 -07:00
|
|
|
let mut subcrates: ~[ValueRef] = ~[];
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 1;
|
2012-01-12 17:59:49 +01:00
|
|
|
let cstore = ccx.sess.cstore;
|
2011-07-27 14:19:39 +02:00
|
|
|
while cstore::have_crate_data(cstore, i) {
|
2012-04-06 18:45:49 +08:00
|
|
|
let cdata = cstore::get_crate_data(cstore, i);
|
2012-07-13 22:57:48 -07:00
|
|
|
let nm = ~"_rust_crate_map_" + cdata.name +
|
2012-07-18 16:18:02 -07:00
|
|
|
~"_" + cstore::get_crate_vers(cstore, i) +
|
|
|
|
~"_" + cstore::get_crate_hash(cstore, i);
|
2012-06-30 16:19:07 -07:00
|
|
|
let cr = str::as_c_str(nm, |buf| {
|
2011-10-25 13:13:55 -07:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
2011-10-20 13:48:10 +02:00
|
|
|
});
|
2012-09-26 17:33:34 -07:00
|
|
|
subcrates.push(p2i(ccx, cr));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
i += 1;
|
|
|
|
}
|
2012-09-26 17:33:34 -07:00
|
|
|
subcrates.push(C_int(ccx, 0));
|
2012-09-21 11:42:47 -07:00
|
|
|
|
|
|
|
let llannihilatefn;
|
|
|
|
let annihilate_def_id = ccx.tcx.lang_items.annihilate_fn.get();
|
|
|
|
if annihilate_def_id.crate == ast::local_crate {
|
|
|
|
llannihilatefn = get_item_val(ccx, annihilate_def_id.node);
|
|
|
|
} else {
|
|
|
|
let annihilate_fn_type = csearch::get_type(ccx.tcx,
|
|
|
|
annihilate_def_id).ty;
|
|
|
|
llannihilatefn = trans_external_path(ccx,
|
|
|
|
annihilate_def_id,
|
|
|
|
annihilate_fn_type);
|
|
|
|
}
|
|
|
|
|
2011-10-25 13:13:55 -07:00
|
|
|
llvm::LLVMSetInitializer(map, C_struct(
|
2012-09-21 11:42:47 -07:00
|
|
|
~[C_i32(1),
|
|
|
|
lib::llvm::llvm::LLVMConstPointerCast(llannihilatefn,
|
|
|
|
T_ptr(T_i8())),
|
|
|
|
p2i(ccx, create_module_map(ccx)),
|
|
|
|
C_array(ccx.int_type, subcrates)]));
|
Make log the log level configurable per module
This overloads the meaning of RUST_LOG to also allow
'module.submodule' or 'module.somethingelse=2' forms. The first turn
on all logging for a module (loglevel 3), the second sets its loglevel
to 2. Log levels are:
0: Show only errors
1: Errors and warnings
2: Errors, warnings, and notes
3: Everything, including debug logging
Right now, since we only have one 'log' operation, everything happens
at level 1 (warning), so the only meaningful thing that can be done
with the new RUST_LOG support is disable logging (=0) for some
modules.
TODOS:
* Language support for logging at a specific level
* Also add a log level field to tasks, query the current task as well
as the current module before logging (log if one of them allows it)
* Revise the C logging API to conform to this set-up (globals for
per-module log level, query the task level before logging, stop
using a global mask)
Implementation notes:
Crates now contain two extra data structures. A 'module map' that
contains names and pointers to the module-log-level globals for each
module in the crate that logs, and a 'crate map' that points at the
crate's module map, as well as at the crate maps of all external
crates it depends on. These are walked by the runtime (in
rust_crate.cpp) to set the currect log levels based on RUST_LOG.
These module log globals are allocated as-needed whenever a log
expression is encountered, and their location is hard-coded into the
logging code, which compares the current level to the log statement's
level, and skips over all logging code when it is lower.
2011-04-17 16:29:18 +02:00
|
|
|
}
|
|
|
|
|
2012-05-13 17:01:52 -07:00
|
|
|
fn crate_ctxt_to_encode_parms(cx: @crate_ctxt)
|
|
|
|
-> encoder::encode_parms {
|
|
|
|
|
2012-05-14 17:46:45 -07:00
|
|
|
let encode_inlined_item =
|
2012-06-30 16:19:07 -07:00
|
|
|
|a,b,c,d| astencode::encode_inlined_item(a, b, c, d, cx.maps);
|
2012-05-14 17:46:45 -07:00
|
|
|
|
2012-08-01 17:30:05 -07:00
|
|
|
return {
|
2012-05-14 20:41:33 -07:00
|
|
|
diag: cx.sess.diagnostic(),
|
2012-05-13 17:01:52 -07:00
|
|
|
tcx: cx.tcx,
|
|
|
|
reachable: cx.reachable,
|
2012-08-17 12:41:34 -07:00
|
|
|
reexports2: cx.exp_map2,
|
2012-05-13 17:01:52 -07:00
|
|
|
item_symbols: cx.item_symbols,
|
|
|
|
discrim_symbols: cx.discrim_symbols,
|
|
|
|
link_meta: cx.link_meta,
|
|
|
|
cstore: cx.sess.cstore,
|
2012-05-14 17:46:45 -07:00
|
|
|
encode_inlined_item: encode_inlined_item
|
2012-05-16 21:50:17 -07:00
|
|
|
};
|
2012-05-13 17:01:52 -07:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn write_metadata(cx: @crate_ctxt, crate: @ast::crate) {
|
2012-08-01 17:30:05 -07:00
|
|
|
if !cx.sess.building_library { return; }
|
2012-05-13 17:01:52 -07:00
|
|
|
let encode_parms = crate_ctxt_to_encode_parms(cx);
|
|
|
|
let llmeta = C_bytes(encoder::encode_metadata(encode_parms, crate));
|
2012-06-29 16:26:56 -07:00
|
|
|
let llconst = C_struct(~[llmeta]);
|
2012-07-13 22:57:48 -07:00
|
|
|
let mut llglobal = str::as_c_str(~"rust_metadata", |buf| {
|
2012-01-27 13:17:06 +01:00
|
|
|
llvm::LLVMAddGlobal(cx.llmod, val_ty(llconst), buf)
|
|
|
|
});
|
2011-06-27 16:09:28 -07:00
|
|
|
llvm::LLVMSetInitializer(llglobal, llconst);
|
2012-06-30 16:19:07 -07:00
|
|
|
str::as_c_str(cx.sess.targ_cfg.target_strs.meta_sect_name, |buf| {
|
2012-01-27 13:17:06 +01:00
|
|
|
llvm::LLVMSetSection(llglobal, buf)
|
|
|
|
});
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(llglobal, lib::llvm::InternalLinkage);
|
2011-07-20 14:52:31 -04:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let t_ptr_i8 = T_ptr(T_i8());
|
2011-07-20 14:52:31 -04:00
|
|
|
llglobal = llvm::LLVMConstBitCast(llglobal, t_ptr_i8);
|
2012-07-13 22:57:48 -07:00
|
|
|
let llvm_used = str::as_c_str(~"llvm.used", |buf| {
|
2012-02-01 11:04:56 +01:00
|
|
|
llvm::LLVMAddGlobal(cx.llmod, T_array(t_ptr_i8, 1u), buf)
|
|
|
|
});
|
|
|
|
lib::llvm::SetLinkage(llvm_used, lib::llvm::AppendingLinkage);
|
2012-06-29 16:26:56 -07:00
|
|
|
llvm::LLVMSetInitializer(llvm_used, C_array(t_ptr_i8, ~[llglobal]));
|
2011-06-27 16:09:28 -07:00
|
|
|
}
|
|
|
|
|
2011-08-20 14:22:09 -07:00
|
|
|
// Writes the current ABI version into the crate.
|
2012-03-14 17:31:16 -07:00
|
|
|
fn write_abi_version(ccx: @crate_ctxt) {
|
2012-07-13 22:57:48 -07:00
|
|
|
mk_global(ccx, ~"rust_abi_version", C_uint(ccx, abi::abi_version),
|
2011-08-20 14:22:09 -07:00
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2012-08-17 12:41:34 -07:00
|
|
|
fn trans_crate(sess: session::session,
|
|
|
|
crate: @ast::crate,
|
|
|
|
tcx: ty::ctxt,
|
2012-08-24 15:28:43 -07:00
|
|
|
output: &Path,
|
2012-08-29 13:26:26 -07:00
|
|
|
emap2: resolve::ExportMap2,
|
2012-05-14 17:46:45 -07:00
|
|
|
maps: astencode::maps)
|
2012-08-17 12:41:34 -07:00
|
|
|
-> (ModuleRef, link_meta) {
|
|
|
|
|
2012-08-02 17:17:31 -07:00
|
|
|
let symbol_hasher = @hash::default_state();
|
2012-07-30 11:26:20 -07:00
|
|
|
let link_meta =
|
2012-09-18 11:46:39 -07:00
|
|
|
link::build_link_meta(sess, *crate, output, symbol_hasher);
|
2012-09-20 13:08:45 -07:00
|
|
|
let reachable = reachable::find_reachable(crate.node.module, emap2, tcx,
|
2012-03-20 12:28:46 +01:00
|
|
|
maps.method_map);
|
2011-12-05 14:56:11 +08:00
|
|
|
|
|
|
|
// Append ".rc" to crate name as LLVM module identifier.
|
|
|
|
//
|
|
|
|
// LLVM code generator emits a ".file filename" directive
|
|
|
|
// for ELF backends. Value of the "filename" is set as the
|
|
|
|
// LLVM module identifier. Due to a LLVM MC bug[1], LLVM
|
|
|
|
// crashes if the module identifer is same as other symbols
|
2011-12-05 11:21:44 -08:00
|
|
|
// such as a function name in the module.
|
2011-12-05 14:56:11 +08:00
|
|
|
// 1. http://llvm.org/bugs/show_bug.cgi?id=11479
|
2012-07-18 16:18:02 -07:00
|
|
|
let llmod_id = link_meta.name + ~".rc";
|
2011-12-05 14:56:11 +08:00
|
|
|
|
2012-06-30 16:19:07 -07:00
|
|
|
let llmod = str::as_c_str(llmod_id, |buf| {
|
2011-09-12 12:39:38 +02:00
|
|
|
llvm::LLVMModuleCreateWithNameInContext
|
|
|
|
(buf, llvm::LLVMGetGlobalContext())
|
|
|
|
});
|
2012-01-12 17:59:49 +01:00
|
|
|
let data_layout = sess.targ_cfg.target_strs.data_layout;
|
|
|
|
let targ_triple = sess.targ_cfg.target_strs.target_triple;
|
2011-09-02 15:34:58 -07:00
|
|
|
let _: () =
|
2012-03-14 15:10:34 -07:00
|
|
|
str::as_c_str(data_layout,
|
2012-06-30 16:19:07 -07:00
|
|
|
|buf| llvm::LLVMSetDataLayout(llmod, buf));
|
2011-09-02 15:34:58 -07:00
|
|
|
let _: () =
|
2012-03-14 15:10:34 -07:00
|
|
|
str::as_c_str(targ_triple,
|
2012-06-30 16:19:07 -07:00
|
|
|
|buf| llvm::LLVMSetTarget(llmod, buf));
|
2012-01-12 17:59:49 +01:00
|
|
|
let targ_cfg = sess.targ_cfg;
|
|
|
|
let td = mk_target_data(sess.targ_cfg.target_strs.data_layout);
|
2011-07-27 14:19:39 +02:00
|
|
|
let tn = mk_type_names();
|
|
|
|
let intrinsics = declare_intrinsics(llmod);
|
2012-01-12 17:59:49 +01:00
|
|
|
if sess.opts.extra_debuginfo {
|
2011-11-15 21:11:22 -05:00
|
|
|
declare_dbg_intrinsics(llmod, intrinsics);
|
|
|
|
}
|
2011-10-14 20:38:24 -07:00
|
|
|
let int_type = T_int(targ_cfg);
|
|
|
|
let float_type = T_float(targ_cfg);
|
|
|
|
let task_type = T_task(targ_cfg);
|
2011-10-14 17:00:17 -07:00
|
|
|
let taskptr_type = T_ptr(task_type);
|
2012-07-13 22:57:48 -07:00
|
|
|
lib::llvm::associate_type(tn, ~"taskptr", taskptr_type);
|
2011-10-25 13:13:55 -07:00
|
|
|
let tydesc_type = T_tydesc(targ_cfg);
|
2012-07-13 22:57:48 -07:00
|
|
|
lib::llvm::associate_type(tn, ~"tydesc", tydesc_type);
|
2012-04-06 18:45:49 +08:00
|
|
|
let crate_map = decl_crate_map(sess, link_meta, llmod);
|
2012-01-12 17:59:49 +01:00
|
|
|
let dbg_cx = if sess.opts.debuginfo {
|
2012-08-20 12:23:37 -07:00
|
|
|
option::Some(debuginfo::mk_ctxt(llmod_id, sess.parse_sess.interner))
|
2011-12-09 11:32:23 -05:00
|
|
|
} else {
|
2012-08-20 12:23:37 -07:00
|
|
|
option::None
|
2011-12-09 11:32:23 -05:00
|
|
|
};
|
2012-02-14 15:21:53 -08:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let ccx =
|
|
|
|
@{sess: sess,
|
|
|
|
llmod: llmod,
|
|
|
|
td: td,
|
|
|
|
tn: tn,
|
2012-09-19 09:41:06 -07:00
|
|
|
externs: HashMap(),
|
2011-07-27 14:19:39 +02:00
|
|
|
intrinsics: intrinsics,
|
2012-09-19 09:41:06 -07:00
|
|
|
item_vals: HashMap(),
|
2012-08-17 12:41:34 -07:00
|
|
|
exp_map2: emap2,
|
2012-03-20 12:28:46 +01:00
|
|
|
reachable: reachable,
|
2012-09-19 09:41:06 -07:00
|
|
|
item_symbols: HashMap(),
|
2012-08-20 12:23:37 -07:00
|
|
|
mut main_fn: None::<ValueRef>,
|
2011-10-20 13:48:10 +02:00
|
|
|
link_meta: link_meta,
|
2012-01-25 14:34:31 +01:00
|
|
|
enum_sizes: ty::new_ty_hash(),
|
2012-09-19 15:13:04 -07:00
|
|
|
discrims: HashMap(),
|
2012-09-19 09:41:06 -07:00
|
|
|
discrim_symbols: HashMap(),
|
2011-12-22 14:24:36 +01:00
|
|
|
tydescs: ty::new_ty_hash(),
|
2012-08-24 15:31:33 -07:00
|
|
|
mut finished_tydescs: false,
|
2012-09-19 15:13:04 -07:00
|
|
|
external: HashMap(),
|
|
|
|
monomorphized: HashMap(),
|
|
|
|
monomorphizing: HashMap(),
|
|
|
|
type_use_cache: HashMap(),
|
2012-09-10 15:38:28 -07:00
|
|
|
vtables: map::HashMap(),
|
2012-09-19 15:13:04 -07:00
|
|
|
const_cstr_cache: HashMap(),
|
2012-09-19 09:41:06 -07:00
|
|
|
const_globals: HashMap(),
|
|
|
|
module_data: HashMap(),
|
2011-12-22 14:24:36 +01:00
|
|
|
lltypes: ty::new_ty_hash(),
|
2012-07-18 16:18:02 -07:00
|
|
|
names: new_namegen(sess.parse_sess.interner),
|
2012-08-06 10:53:38 -07:00
|
|
|
next_addrspace: new_addrspace_gen(),
|
2012-07-28 23:37:11 +02:00
|
|
|
symbol_hasher: symbol_hasher,
|
|
|
|
type_hashcodes: ty::new_ty_hash(),
|
2011-12-22 14:24:36 +01:00
|
|
|
type_short_names: ty::new_ty_hash(),
|
2012-09-19 09:41:06 -07:00
|
|
|
all_llvm_symbols: HashMap(),
|
2011-07-27 14:19:39 +02:00
|
|
|
tcx: tcx,
|
2012-02-14 15:21:53 -08:00
|
|
|
maps: maps,
|
2011-07-27 14:19:39 +02:00
|
|
|
stats:
|
2012-03-26 18:35:18 -07:00
|
|
|
{mut n_static_tydescs: 0u,
|
|
|
|
mut n_glues_created: 0u,
|
|
|
|
mut n_null_glues: 0u,
|
|
|
|
mut n_real_glues: 0u,
|
2012-09-12 14:48:13 -07:00
|
|
|
mut n_fns: 0u,
|
|
|
|
mut n_monos: 0u,
|
|
|
|
mut n_inlines: 0u,
|
|
|
|
mut n_closures: 0u,
|
2012-06-29 16:26:56 -07:00
|
|
|
llvm_insn_ctxt: @mut ~[],
|
2012-09-19 15:13:04 -07:00
|
|
|
llvm_insns: HashMap(),
|
2012-06-29 16:26:56 -07:00
|
|
|
fn_times: @mut ~[]},
|
2011-07-27 14:19:39 +02:00
|
|
|
upcalls:
|
2011-10-14 20:38:24 -07:00
|
|
|
upcall::declare_upcalls(targ_cfg, tn, tydesc_type,
|
|
|
|
llmod),
|
2012-09-19 09:41:06 -07:00
|
|
|
rtcalls: HashMap(),
|
2011-07-27 14:19:39 +02:00
|
|
|
tydesc_type: tydesc_type,
|
2011-10-14 17:00:17 -07:00
|
|
|
int_type: int_type,
|
|
|
|
float_type: float_type,
|
2011-08-04 10:46:10 -07:00
|
|
|
task_type: task_type,
|
2011-10-14 20:38:24 -07:00
|
|
|
opaque_vec_type: T_opaque_vec(targ_cfg),
|
2011-08-24 16:30:20 +02:00
|
|
|
builder: BuilderRef_res(llvm::LLVMCreateBuilder()),
|
2012-02-10 11:32:03 +01:00
|
|
|
shape_cx: mk_ctxt(llmod),
|
2011-11-10 00:55:09 -05:00
|
|
|
crate_map: crate_map,
|
2012-07-16 12:28:15 -07:00
|
|
|
mut uses_gc: false,
|
2012-02-01 18:52:08 -08:00
|
|
|
dbg_cx: dbg_cx,
|
2012-10-08 09:00:23 -07:00
|
|
|
class_ctors: HashMap(),
|
2012-03-26 18:35:18 -07:00
|
|
|
mut do_not_commit_warning_issued: false};
|
2012-03-22 13:44:20 -07:00
|
|
|
|
|
|
|
|
2012-07-10 15:52:05 -07:00
|
|
|
gather_rtcalls(ccx, crate);
|
|
|
|
|
2012-03-22 13:44:20 -07:00
|
|
|
{
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("data");
|
2012-03-22 13:44:20 -07:00
|
|
|
trans_constants(ccx, crate);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
2012-08-14 16:45:43 -07:00
|
|
|
let _icx = ccx.insn_ctxt("text");
|
2012-03-22 13:44:20 -07:00
|
|
|
trans_mod(ccx, crate.node.module);
|
|
|
|
}
|
|
|
|
|
2012-07-16 12:28:15 -07:00
|
|
|
decl_gc_metadata(ccx, llmod_id);
|
2011-10-20 13:48:10 +02:00
|
|
|
fill_crate_map(ccx, crate_map);
|
2012-08-28 15:54:45 -07:00
|
|
|
glue::emit_tydescs(ccx);
|
2011-08-20 14:22:09 -07:00
|
|
|
write_abi_version(ccx);
|
2011-03-11 15:35:20 -08:00
|
|
|
|
2011-08-04 11:25:09 -07:00
|
|
|
// Translate the metadata.
|
2012-02-03 09:53:37 +01:00
|
|
|
write_metadata(ccx, crate);
|
2012-07-05 12:59:03 -07:00
|
|
|
if ccx.sess.trans_stats() {
|
2012-07-13 22:57:48 -07:00
|
|
|
io::println(~"--- trans stats ---");
|
2012-08-22 17:24:52 -07:00
|
|
|
io::println(fmt!("n_static_tydescs: %u",
|
|
|
|
ccx.stats.n_static_tydescs));
|
|
|
|
io::println(fmt!("n_glues_created: %u",
|
|
|
|
ccx.stats.n_glues_created));
|
|
|
|
io::println(fmt!("n_null_glues: %u", ccx.stats.n_null_glues));
|
|
|
|
io::println(fmt!("n_real_glues: %u", ccx.stats.n_real_glues));
|
2011-07-19 11:56:46 -07:00
|
|
|
|
2012-09-12 14:48:13 -07:00
|
|
|
io::println(fmt!("n_fns: %u", ccx.stats.n_fns));
|
|
|
|
io::println(fmt!("n_monos: %u", ccx.stats.n_monos));
|
|
|
|
io::println(fmt!("n_inlines: %u", ccx.stats.n_inlines));
|
|
|
|
io::println(fmt!("n_closures: %u", ccx.stats.n_closures));
|
2012-03-22 13:44:20 -07:00
|
|
|
}
|
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if ccx.sess.count_llvm_insns() {
|
2012-06-30 16:19:07 -07:00
|
|
|
for ccx.stats.llvm_insns.each |k, v| {
|
2012-08-22 17:24:52 -07:00
|
|
|
io::println(fmt!("%-7u %s", v, k));
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
2012-08-01 17:30:05 -07:00
|
|
|
return (llmod, link_meta);
|
2010-09-22 15:21:06 -07:00
|
|
|
}
|
|
|
|
//
|
|
|
|
// Local Variables:
|
|
|
|
// mode: rust
|
|
|
|
// fill-column: 78;
|
|
|
|
// indent-tabs-mode: nil
|
|
|
|
// c-basic-offset: 4
|
|
|
|
// buffer-file-coding-system: utf-8-unix
|
|
|
|
// End:
|
|
|
|
//
|