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-06-07 14:37:36 -07:00
|
|
|
import libc::{c_uint, c_ulonglong};
|
2012-05-16 22:28:01 -07:00
|
|
|
import std::{map, time, list};
|
2011-05-12 17:24:54 +02:00
|
|
|
import std::map::hashmap;
|
2012-03-14 12:07:23 -07:00
|
|
|
import std::map::{int_hash, str_hash};
|
2011-05-12 17:24:54 +02:00
|
|
|
import driver::session;
|
2012-01-12 17:59:49 +01:00
|
|
|
import session::session;
|
2012-03-22 18:16:22 -07:00
|
|
|
import syntax::attr;
|
2011-11-11 00:41:42 +08:00
|
|
|
import back::{link, abi, upcall};
|
2012-05-21 23:34:34 -07:00
|
|
|
import syntax::{ast, ast_util, codemap, ast_map};
|
2012-05-21 22:41:59 -07:00
|
|
|
import ast_util::{inlined_item_methods, local_def, path_to_ident};
|
2011-07-05 11:48:19 +02:00
|
|
|
import syntax::visit;
|
2011-09-12 16:13:28 -07:00
|
|
|
import syntax::codemap::span;
|
2012-01-14 16:05:07 -08:00
|
|
|
import syntax::print::pprust::{expr_to_str, stmt_to_str, path_to_str};
|
|
|
|
import pat_util::*;
|
2011-06-10 17:24:20 +02:00
|
|
|
import visit::vt;
|
2012-06-08 16:53:01 -07:00
|
|
|
import util::common::is_main_name;
|
2011-11-11 00:41:42 +08:00
|
|
|
import lib::llvm::{llvm, mk_target_data, mk_type_names};
|
2012-02-01 11:04:56 +01:00
|
|
|
import lib::llvm::{ModuleRef, ValueRef, TypeRef, BasicBlockRef};
|
2011-11-11 00:41:42 +08:00
|
|
|
import lib::llvm::{True, False};
|
2011-09-12 16:13:28 -07:00
|
|
|
import link::{mangle_internal_name_by_type_only,
|
|
|
|
mangle_internal_name_by_seq,
|
|
|
|
mangle_internal_name_by_path,
|
|
|
|
mangle_internal_name_by_path_and_seq,
|
|
|
|
mangle_exported_name};
|
2012-05-13 17:01:52 -07:00
|
|
|
import metadata::{csearch, cstore, encoder};
|
2012-05-17 16:17:11 -07:00
|
|
|
import metadata::common::link_meta;
|
2011-09-12 16:13:28 -07:00
|
|
|
import util::ppaux::{ty_to_str, ty_to_short_str};
|
2012-05-29 14:39:22 -07:00
|
|
|
import syntax::diagnostic::expect;
|
2011-06-07 17:54:22 -07:00
|
|
|
|
2012-01-27 13:17:06 +01:00
|
|
|
import common::*;
|
|
|
|
import build::*;
|
2012-02-10 11:32:03 +01:00
|
|
|
import shape::*;
|
2012-02-21 15:22:55 +01:00
|
|
|
import type_of::*;
|
|
|
|
import type_of::type_of; // Issue #1873
|
2012-05-21 23:34:34 -07:00
|
|
|
import syntax::ast_map::{path, path_mod, path_name};
|
2011-08-09 16:42:55 -07:00
|
|
|
|
2012-03-03 17:49:23 -08:00
|
|
|
import std::smallintmap;
|
2012-06-12 14:55:44 -07:00
|
|
|
import option::is_none;
|
2012-03-03 17:49:23 -08:00
|
|
|
|
2012-02-21 15:22:55 +01:00
|
|
|
// Destinations
|
|
|
|
|
|
|
|
// These are passed around by the code generating functions to track the
|
|
|
|
// destination of a computation's value.
|
|
|
|
|
|
|
|
enum dest {
|
2012-03-26 18:35:18 -07:00
|
|
|
by_val(@mut ValueRef),
|
2012-02-21 15:22:55 +01:00
|
|
|
save_in(ValueRef),
|
|
|
|
ignore,
|
2011-02-16 16:16:11 -05:00
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2012-06-06 18:22:49 -07:00
|
|
|
// Heap selectors. Indicate which heap something should go on.
|
|
|
|
enum heap {
|
|
|
|
heap_shared,
|
|
|
|
heap_exchange,
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn dest_str(ccx: @crate_ctxt, d: dest) -> str {
|
2012-02-14 15:21:53 -08:00
|
|
|
alt d {
|
|
|
|
by_val(v) { #fmt["by_val(%s)", val_str(ccx.tn, *v)] }
|
|
|
|
save_in(v) { #fmt["save_in(%s)", val_str(ccx.tn, v)] }
|
|
|
|
ignore { "ignore" }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-26 18:35:18 -07:00
|
|
|
fn empty_dest_cell() -> @mut ValueRef {
|
|
|
|
ret @mut llvm::LLVMGetUndef(T_nil());
|
2012-02-21 15:22:55 +01:00
|
|
|
}
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-02-21 15:22:55 +01:00
|
|
|
fn dup_for_join(dest: dest) -> dest {
|
|
|
|
alt dest {
|
|
|
|
by_val(_) { by_val(empty_dest_cell()) }
|
|
|
|
_ { dest }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-22 13:44:20 -07:00
|
|
|
resource icx_popper(ccx: @crate_ctxt) {
|
2012-05-17 21:53:49 -07:00
|
|
|
if ccx.sess.count_llvm_insns() {
|
2012-03-22 13:44:20 -07:00
|
|
|
vec::pop(*ccx.stats.llvm_insn_ctxt);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl ccx_icx for @crate_ctxt {
|
|
|
|
fn insn_ctxt(s: str) -> icx_popper {
|
2012-05-07 14:27:43 -07:00
|
|
|
#debug("new insn_ctxt: %s", s);
|
2012-05-17 21:53:49 -07:00
|
|
|
if self.sess.count_llvm_insns() {
|
2012-03-22 13:44:20 -07:00
|
|
|
*self.stats.llvm_insn_ctxt += [s];
|
|
|
|
}
|
|
|
|
icx_popper(self)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl bcx_icx for block {
|
|
|
|
fn insn_ctxt(s: str) -> icx_popper {
|
|
|
|
self.ccx().insn_ctxt(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl fcx_icx for fn_ctxt {
|
|
|
|
fn insn_ctxt(s: str) -> icx_popper {
|
|
|
|
self.ccx.insn_ctxt(s)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-21 15:22:55 +01:00
|
|
|
fn join_returns(parent_cx: block, in_cxs: [block],
|
|
|
|
in_ds: [dest], out_dest: dest) -> block {
|
|
|
|
let out = sub_block(parent_cx, "join");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut reachable = false, i = 0u, phi = none;
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(in_cxs) {|cx|
|
2012-02-21 15:22:55 +01:00
|
|
|
if !cx.unreachable {
|
|
|
|
Br(cx, out.llbb);
|
|
|
|
reachable = true;
|
|
|
|
alt in_ds[i] {
|
|
|
|
by_val(cell) {
|
|
|
|
if option::is_none(phi) {
|
|
|
|
phi = some(EmptyPhi(out, val_ty(*cell)));
|
|
|
|
}
|
|
|
|
AddIncomingToPhi(option::get(phi), *cell, cx.llbb);
|
|
|
|
}
|
2012-01-13 10:58:31 +01:00
|
|
|
_ {}
|
2012-01-02 16:50:51 +01:00
|
|
|
}
|
2012-01-02 12:00:40 +01:00
|
|
|
}
|
2012-02-21 15:22:55 +01:00
|
|
|
i += 1u;
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2012-02-21 15:22:55 +01:00
|
|
|
if !reachable {
|
|
|
|
Unreachable(out);
|
|
|
|
} else {
|
|
|
|
alt out_dest {
|
|
|
|
by_val(cell) { *cell = option::get(phi); }
|
|
|
|
_ {}
|
2011-09-15 20:47:38 -07:00
|
|
|
}
|
2011-09-17 09:12:26 -07:00
|
|
|
}
|
2012-02-21 15:22:55 +01:00
|
|
|
ret out;
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
|
|
|
|
2012-02-21 15:22:55 +01:00
|
|
|
// Used to put an immediate value in a dest.
|
|
|
|
fn store_in_dest(bcx: block, val: ValueRef, dest: dest) -> block {
|
|
|
|
alt dest {
|
|
|
|
ignore {}
|
|
|
|
by_val(cell) { *cell = val; }
|
|
|
|
save_in(addr) { Store(bcx, val, addr); }
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
2012-02-21 15:22:55 +01:00
|
|
|
ret bcx;
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
2012-02-21 15:22:55 +01:00
|
|
|
fn get_dest_addr(dest: dest) -> ValueRef {
|
|
|
|
alt dest {
|
|
|
|
save_in(a) { a }
|
|
|
|
_ { fail "get_dest_addr: not a save_in"; }
|
|
|
|
}
|
2011-09-12 11:27:30 +02:00
|
|
|
}
|
2011-06-10 19:35:59 -07:00
|
|
|
|
2012-04-02 21:41:24 -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;
|
2011-08-19 15:16:48 -07:00
|
|
|
*ccx.stats.fn_times += [{ident: name, time: elapsed}];
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-01 11:04:56 +01:00
|
|
|
fn decl_fn(llmod: ModuleRef, name: str, cc: lib::llvm::CallConv,
|
|
|
|
llty: TypeRef) -> ValueRef {
|
2012-03-14 15:10:34 -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);
|
2010-09-23 17:16:34 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn decl_cdecl_fn(llmod: ModuleRef, name: str, llty: TypeRef) -> ValueRef {
|
2012-02-01 11:04:56 +01:00
|
|
|
ret decl_fn(llmod, name, lib::llvm::CCallConv, llty);
|
2010-11-14 12:28:07 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07: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.
|
2011-09-27 18:42:06 -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);
|
2011-03-26 19:14:07 -07:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn get_extern_fn(externs: hashmap<str, ValueRef>, llmod: ModuleRef, name: str,
|
2012-02-01 11:04:56 +01:00
|
|
|
cc: lib::llvm::CallConv, ty: TypeRef) -> ValueRef {
|
2011-09-02 15:34:58 -07:00
|
|
|
if externs.contains_key(name) { ret 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);
|
2010-09-23 18:38:37 -07:00
|
|
|
ret f;
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn get_extern_const(externs: hashmap<str, ValueRef>, llmod: ModuleRef,
|
|
|
|
name: str, ty: TypeRef) -> ValueRef {
|
2011-09-02 15:34:58 -07:00
|
|
|
if externs.contains_key(name) { ret externs.get(name); }
|
2012-03-14 15:10:34 -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);
|
2011-03-25 17:59:45 -07:00
|
|
|
ret c;
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn get_simple_extern_fn(cx: block,
|
2011-10-14 16:45:25 -07:00
|
|
|
externs: hashmap<str, ValueRef>,
|
|
|
|
llmod: ModuleRef,
|
2011-09-12 11:27:30 +02:00
|
|
|
name: str, n_args: int) -> ValueRef {
|
2012-03-22 13:44:20 -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-02-01 11:04:56 +01:00
|
|
|
ret get_extern_fn(externs, llmod, name, lib::llvm::CCallConv, t);
|
2011-03-25 17:59:45 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_native_call(cx: block, externs: hashmap<str, ValueRef>,
|
2011-09-12 11:27:30 +02:00
|
|
|
llmod: ModuleRef, name: str, args: [ValueRef]) ->
|
2011-08-19 15:16:48 -07:00
|
|
|
ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_native_call");
|
2012-02-14 09:10:47 +01:00
|
|
|
let n = args.len() as int;
|
2011-10-14 16:45:25 -07:00
|
|
|
let llnative: ValueRef =
|
|
|
|
get_simple_extern_fn(cx, externs, llmod, name, n);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut call_args: [ValueRef] = [];
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(args) {|a|
|
2012-04-24 14:00:43 -07:00
|
|
|
call_args += [a];
|
2011-10-14 16:45:25 -07:00
|
|
|
}
|
2011-08-30 09:59:30 +02:00
|
|
|
ret Call(cx, llnative, call_args);
|
2010-09-24 14:56:04 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_free(cx: block, v: ValueRef) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_free");
|
2012-02-21 14:20:18 +01:00
|
|
|
Call(cx, cx.ccx().upcalls.free, [PointerCast(cx, v, T_ptr(T_i8()))]);
|
2012-02-03 09:34:42 +01:00
|
|
|
cx
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
|
|
|
|
2012-05-09 14:11:46 -07:00
|
|
|
fn trans_unique_free(cx: block, v: ValueRef) -> block {
|
|
|
|
let _icx = cx.insn_ctxt("trans_shared_free");
|
|
|
|
Call(cx, cx.ccx().upcalls.exchange_free,
|
|
|
|
[PointerCast(cx, v, T_ptr(T_i8()))]);
|
|
|
|
ret cx;
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn umax(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
|
2012-03-22 13:44:20 -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-01-19 10:37:40 -08:00
|
|
|
ret Select(cx, cond, b, a);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn umin(cx: block, a: ValueRef, b: ValueRef) -> ValueRef {
|
2012-03-22 13:44:20 -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-01-19 10:37:40 -08:00
|
|
|
ret Select(cx, cond, a, b);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn alloca(cx: block, t: TypeRef) -> ValueRef {
|
2012-05-28 20:52:11 -07:00
|
|
|
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 {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("alloca");
|
2011-09-26 03:57:08 +02:00
|
|
|
if cx.unreachable { ret llvm::LLVMGetUndef(t); }
|
2012-05-28 20:52:11 -07:00
|
|
|
let initcx = raw_block(cx.fcx, cx.fcx.llstaticallocas);
|
|
|
|
let p = Alloca(initcx, t);
|
|
|
|
if zero { Store(initcx, C_null(t), p); }
|
|
|
|
ret p;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn zero_mem(cx: block, llptr: ValueRef, t: ty::t) -> block {
|
|
|
|
let _icx = cx.insn_ctxt("zero_mem");
|
|
|
|
let bcx = cx;
|
|
|
|
let ccx = cx.ccx();
|
|
|
|
let llty = type_of(ccx, t);
|
|
|
|
Store(bcx, C_null(llty), llptr);
|
|
|
|
ret bcx;
|
2011-03-28 18:04:52 -07:00
|
|
|
}
|
|
|
|
|
2012-04-19 15:42:02 -07:00
|
|
|
fn arrayalloca(cx: block, t: TypeRef, v: ValueRef) -> ValueRef {
|
|
|
|
let _icx = cx.insn_ctxt("arrayalloca");
|
|
|
|
if cx.unreachable { ret llvm::LLVMGetUndef(t); }
|
|
|
|
ret ArrayAlloca(raw_block(cx.fcx, cx.fcx.llstaticallocas), t, v);
|
|
|
|
}
|
|
|
|
|
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-03-22 13:44:20 -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-03-05 15:12:36 -08: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-03-22 13:44:20 -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,
|
|
|
|
variant_id: ast::def_id, ty_substs: [ty::t],
|
2012-03-23 14:45:47 +01:00
|
|
|
ix: uint) -> ValueRef {
|
2012-03-22 13:44:20 -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-03-12 09:26:54 +01:00
|
|
|
let arg_lltys = vec::map(variant.args, {|aty|
|
2012-04-18 21:26:25 -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-05-03 22:31:38 -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-03-22 13:44:20 -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-05-03 22:31:38 -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-06 18:22:49 -07:00
|
|
|
// malloc_raw: expects an unboxed type and returns a pointer to
|
2012-02-01 18:52:08 -08:00
|
|
|
// enough space for a box of that type. This includes a rust_opaque_box
|
|
|
|
// header.
|
2012-06-06 18:22:49 -07:00
|
|
|
fn malloc_raw(bcx: block, t: ty::t, heap: heap) -> ValueRef {
|
|
|
|
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-06-06 18:22:49 -07:00
|
|
|
let (mk_fn, upcall) = alt heap {
|
|
|
|
heap_shared { (ty::mk_imm_box, ccx.upcalls.malloc) }
|
|
|
|
heap_exchange {
|
|
|
|
(ty::mk_imm_uniq, ccx.upcalls.exchange_malloc )
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
// 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-06-06 18:22:49 -07:00
|
|
|
let mut static_ti = none;
|
2012-03-21 15:42:20 +01:00
|
|
|
let lltydesc = get_tydesc(ccx, t, static_ti);
|
2012-05-12 19:31:28 -07:00
|
|
|
lazily_emit_all_tydesc_glue(ccx, copy static_ti);
|
2011-09-20 13:48:22 -07:00
|
|
|
|
2012-02-01 18:52:08 -08:00
|
|
|
// Allocate space:
|
2012-06-06 18:22:49 -07:00
|
|
|
let rval = Call(bcx, upcall, [lltydesc]);
|
2012-03-23 14:45:47 +01:00
|
|
|
ret PointerCast(bcx, rval, llty);
|
2010-12-02 17:43:05 -08:00
|
|
|
}
|
|
|
|
|
2012-06-06 18:22:49 -07:00
|
|
|
// malloc_general: usefully wraps malloc_raw; allocates a box,
|
|
|
|
// and pulls out the body
|
|
|
|
fn malloc_general(bcx: block, t: ty::t, heap: heap) ->
|
|
|
|
{box: ValueRef, body: ValueRef} {
|
|
|
|
let _icx = bcx.insn_ctxt("malloc_general");
|
|
|
|
let box = malloc_raw(bcx, t, heap);
|
2012-06-12 16:41:20 -07:00
|
|
|
let non_gc_box = non_gc_box_cast(bcx, box);
|
2012-06-06 18:22:49 -07:00
|
|
|
let body = GEPi(bcx, non_gc_box, [0u, abi::box_field_body]);
|
2012-03-23 14:45:47 +01:00
|
|
|
ret {box: box, body: body};
|
2011-07-28 15:44:51 -07:00
|
|
|
}
|
2010-12-02 17:43:05 -08:00
|
|
|
|
2012-06-06 18:22:49 -07:00
|
|
|
fn malloc_boxed(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
|
|
|
malloc_general(bcx, t, heap_shared)
|
2012-05-09 12:32:34 -07:00
|
|
|
}
|
|
|
|
fn malloc_unique(bcx: block, t: ty::t) -> {box: ValueRef, body: ValueRef} {
|
2012-06-06 18:22:49 -07:00
|
|
|
malloc_general(bcx, t, heap_exchange)
|
2012-05-09 12:32:34 -07:00
|
|
|
}
|
|
|
|
|
2012-05-21 18:36:52 -07:00
|
|
|
fn malloc_unique_dyn_raw(bcx: block, t: ty::t, size: ValueRef) -> ValueRef {
|
2012-06-06 18:22:49 -07:00
|
|
|
let _icx = bcx.insn_ctxt("malloc_unique_dyn_raw");
|
2012-05-21 18:36:52 -07:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
2012-06-06 18:22:49 -07:00
|
|
|
// Grab the TypeRef type of box_ptr_ty.
|
|
|
|
let box_ptr_ty = ty::mk_imm_uniq(ccx.tcx, t);
|
|
|
|
let llty = type_of(ccx, box_ptr_ty);
|
2012-05-21 18:36:52 -07:00
|
|
|
|
|
|
|
// Get the tydesc for the body:
|
|
|
|
let mut static_ti = none;
|
|
|
|
let lltydesc = get_tydesc(ccx, t, static_ti);
|
|
|
|
lazily_emit_all_tydesc_glue(ccx, static_ti);
|
|
|
|
|
|
|
|
// Allocate space:
|
|
|
|
let rval = Call(bcx, ccx.upcalls.exchange_malloc_dyn, [lltydesc, size]);
|
|
|
|
ret PointerCast(bcx, rval, llty);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn malloc_unique_dyn(bcx: block, t: ty::t, size: ValueRef
|
|
|
|
) -> {box: ValueRef, body: ValueRef} {
|
2012-06-06 18:22:49 -07:00
|
|
|
let _icx = bcx.insn_ctxt("malloc_unique_dyn");
|
2012-05-21 18:36:52 -07:00
|
|
|
let box = malloc_unique_dyn_raw(bcx, t, size);
|
|
|
|
let body = GEPi(bcx, box, [0u, abi::box_field_body]);
|
|
|
|
ret {box: box, body: body};
|
|
|
|
}
|
|
|
|
|
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-03-15 09:47:03 -04:00
|
|
|
let mut ti = none;
|
2012-03-21 15:42:20 +01:00
|
|
|
get_tydesc(ccx, t, ti)
|
2012-02-17 15:45:38 +01:00
|
|
|
}
|
2011-08-17 19:11:01 -07:00
|
|
|
|
2012-03-21 15:42:20 +01:00
|
|
|
fn get_tydesc(ccx: @crate_ctxt, t: ty::t,
|
|
|
|
&static_ti: option<@tydesc_info>) -> ValueRef {
|
2012-03-08 19:02:22 +01:00
|
|
|
assert !ty::type_has_params(t);
|
2011-06-29 17:29:24 -07:00
|
|
|
// Otherwise, generate a tydesc if necessary, and return it.
|
2012-04-19 16:19:53 -07:00
|
|
|
let inf = get_static_tydesc(ccx, t);
|
|
|
|
static_ti = some(inf);
|
|
|
|
inf.tydesc
|
2011-04-26 17:19:44 -07:00
|
|
|
}
|
|
|
|
|
2012-03-11 12:06:05 +01:00
|
|
|
fn get_static_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
2012-02-07 11:25:04 +01:00
|
|
|
alt ccx.tydescs.find(t) {
|
2012-04-19 16:19:53 -07:00
|
|
|
some(inf) { ret inf; }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2012-02-07 11:25:04 +01:00
|
|
|
ccx.stats.n_static_tydescs += 1u;
|
2012-04-19 16:19:53 -07:00
|
|
|
let inf = declare_tydesc(ccx, t);
|
|
|
|
ccx.tydescs.insert(t, inf);
|
|
|
|
ret 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-03-06 11:33:25 +01:00
|
|
|
fn set_inline_hint_if_appr(attrs: [ast::attribute],
|
|
|
|
llfn: ValueRef) {
|
2012-03-02 13:14:10 -08:00
|
|
|
alt attr::find_inline_attr(attrs) {
|
2012-03-06 11:33:25 +01:00
|
|
|
attr::ia_hint { set_inline_hint(llfn); }
|
|
|
|
attr::ia_always { set_always_inline(llfn); }
|
2012-03-02 13:14:10 -08:00
|
|
|
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.
|
|
|
|
fn note_unique_llvm_symbol(ccx: @crate_ctxt, sym: str) {
|
|
|
|
if ccx.all_llvm_symbols.contains_key(sym) {
|
|
|
|
ccx.sess.bug("duplicate LLVM symbol: " + sym);
|
|
|
|
}
|
|
|
|
ccx.all_llvm_symbols.insert(sym, ());
|
|
|
|
}
|
2011-05-20 14:57:52 -07:00
|
|
|
|
2011-05-12 15:42:12 -07:00
|
|
|
// Generates the declaration for (but doesn't emit) a type descriptor.
|
2012-03-11 12:06:05 +01:00
|
|
|
fn declare_tydesc(ccx: @crate_ctxt, t: ty::t) -> @tydesc_info {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("declare_tydesc");
|
2012-02-03 09:53:37 +01:00
|
|
|
log(debug, "+++ declare_tydesc " + ty_to_str(ccx.tcx, t));
|
2012-03-12 10:05:15 +01:00
|
|
|
let llty = type_of(ccx, t);
|
2012-03-15 09:47:03 -04:00
|
|
|
let llsize = llsize_of(ccx, llty);
|
|
|
|
let llalign = llalign_of(ccx, llty);
|
|
|
|
let mut name;
|
2012-03-21 16:10:39 -07:00
|
|
|
//XXX this triggers duplicate LLVM symbols
|
|
|
|
if false /*ccx.sess.opts.debuginfo*/ {
|
2012-06-10 00:49:59 -07:00
|
|
|
name = mangle_internal_name_by_type_only(ccx, t, @"tydesc");
|
|
|
|
} else { name = mangle_internal_name_by_seq(ccx, @"tydesc"); }
|
2012-03-20 14:21:02 -07:00
|
|
|
note_unique_llvm_symbol(ccx, name);
|
2012-03-14 15:10:34 -07:00
|
|
|
let gvar = str::as_c_str(name, {|buf|
|
2012-02-03 09:53:37 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.tydesc_type, buf)
|
|
|
|
});
|
2012-04-19 16:19:53 -07:00
|
|
|
let inf =
|
2011-07-27 14:19:39 +02:00
|
|
|
@{ty: t,
|
|
|
|
tydesc: gvar,
|
|
|
|
size: llsize,
|
|
|
|
align: llalign,
|
2012-03-26 18:35:18 -07:00
|
|
|
mut take_glue: none,
|
|
|
|
mut drop_glue: none,
|
2012-05-14 17:57:39 -07:00
|
|
|
mut free_glue: none,
|
|
|
|
mut visit_glue: none};
|
2012-02-03 09:53:37 +01:00
|
|
|
log(debug, "--- declare_tydesc " + ty_to_str(ccx.tcx, t));
|
2012-04-19 16:19:53 -07:00
|
|
|
ret inf;
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
type glue_helper = fn@(block, ValueRef, ty::t);
|
2011-04-18 10:56:52 -07:00
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn declare_generic_glue(ccx: @crate_ctxt, t: ty::t, llfnty: TypeRef,
|
2012-02-03 09:53:37 +01:00
|
|
|
name: str) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("declare_generic_glue");
|
2011-08-26 21:34:56 -07:00
|
|
|
let name = name;
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut fn_nm;
|
2012-03-21 16:10:39 -07:00
|
|
|
//XXX this triggers duplicate LLVM symbols
|
|
|
|
if false /*ccx.sess.opts.debuginfo*/ {
|
2012-06-10 00:49:59 -07:00
|
|
|
fn_nm = mangle_internal_name_by_type_only(ccx, t, @("glue_" + name));
|
2012-03-20 14:21:02 -07:00
|
|
|
} else {
|
2012-06-10 00:49:59 -07:00
|
|
|
fn_nm = mangle_internal_name_by_seq(ccx, @("glue_" + name));
|
2012-03-20 14:21:02 -07:00
|
|
|
}
|
|
|
|
note_unique_llvm_symbol(ccx, fn_nm);
|
2012-02-03 09:53:37 +01:00
|
|
|
let llfn = decl_cdecl_fn(ccx.llmod, fn_nm, llfnty);
|
2012-02-03 15:15:28 +01:00
|
|
|
set_glue_inlining(llfn, t);
|
2011-03-20 15:05:13 -07:00
|
|
|
ret llfn;
|
2011-03-04 17:22:43 -08:00
|
|
|
}
|
2010-12-10 15:02:23 -08:00
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn make_generic_glue_inner(ccx: @crate_ctxt, t: ty::t,
|
2012-03-11 12:06:05 +01:00
|
|
|
llfn: ValueRef, helper: glue_helper) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("make_generic_glue_inner");
|
2012-02-03 09:53:37 +01:00
|
|
|
let fcx = new_fn_ctxt(ccx, [], llfn, none);
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(llfn, lib::llvm::InternalLinkage);
|
2012-02-03 09:53:37 +01:00
|
|
|
ccx.stats.n_glues_created += 1u;
|
2011-04-19 11:25:40 -07:00
|
|
|
// Any nontrivial glue is with values passed *by alias*; this is a
|
|
|
|
// requirement since in many contexts glue is invoked indirectly and
|
|
|
|
// the caller has no idea if it's dealing with something that can be
|
|
|
|
// passed by value.
|
2011-04-12 12:06:20 -07:00
|
|
|
|
2012-03-12 10:05:15 +01:00
|
|
|
let llty = T_ptr(type_of(ccx, t));
|
2011-09-02 18:59:22 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
let bcx = top_scope_block(fcx, none);
|
2011-07-27 14:19:39 +02:00
|
|
|
let lltop = bcx.llbb;
|
2012-01-18 19:29:37 +08:00
|
|
|
let llrawptr0 = llvm::LLVMGetParam(llfn, 3u as c_uint);
|
2011-08-30 09:59:30 +02:00
|
|
|
let llval0 = BitCast(bcx, llrawptr0, llty);
|
2011-12-12 09:39:41 -08:00
|
|
|
helper(bcx, llval0, t);
|
2011-05-11 11:56:49 -07:00
|
|
|
finish_fn(fcx, lltop);
|
2010-12-10 15:02:23 -08:00
|
|
|
ret llfn;
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn make_generic_glue(ccx: @crate_ctxt, t: ty::t, llfn: ValueRef,
|
2012-03-11 12:06:05 +01:00
|
|
|
helper: glue_helper, name: str)
|
2012-02-03 09:53:37 +01:00
|
|
|
-> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("make_generic_glue");
|
2012-05-17 21:53:49 -07:00
|
|
|
if !ccx.sess.stats() {
|
2012-03-11 12:06:05 +01:00
|
|
|
ret make_generic_glue_inner(ccx, t, llfn, helper);
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
let start = time::get_time();
|
2012-03-11 12:06:05 +01:00
|
|
|
let llval = make_generic_glue_inner(ccx, t, llfn, helper);
|
2011-07-27 14:19:39 +02:00
|
|
|
let end = time::get_time();
|
2012-02-03 09:53:37 +01:00
|
|
|
log_fn_time(ccx, "glue " + name + " " + ty_to_short_str(ccx.tcx, t),
|
2011-07-19 11:56:46 -07:00
|
|
|
start, end);
|
|
|
|
ret llval;
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn emit_tydescs(ccx: @crate_ctxt) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("emit_tydescs");
|
2012-04-23 13:42:15 +02:00
|
|
|
for ccx.tydescs.each {|key, val|
|
2011-10-14 16:45:25 -07:00
|
|
|
let glue_fn_ty = T_ptr(T_glue_fn(ccx));
|
2011-10-21 12:21:27 +02:00
|
|
|
let ti = val;
|
2011-08-19 10:24:13 +02:00
|
|
|
let take_glue =
|
2012-05-22 05:20:47 -07:00
|
|
|
alt copy ti.take_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let drop_glue =
|
2012-05-22 05:20:47 -07:00
|
|
|
alt copy ti.drop_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let free_glue =
|
2012-05-22 05:20:47 -07:00
|
|
|
alt copy ti.free_glue {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
2011-06-15 11:19:50 -07:00
|
|
|
};
|
2012-05-14 17:57:39 -07:00
|
|
|
let visit_glue =
|
2012-05-22 05:20:47 -07:00
|
|
|
alt copy ti.visit_glue {
|
2012-05-14 17:57:39 -07:00
|
|
|
none { ccx.stats.n_null_glues += 1u; C_null(glue_fn_ty) }
|
|
|
|
some(v) { ccx.stats.n_real_glues += 1u; v }
|
|
|
|
};
|
2011-08-04 11:25:09 -07:00
|
|
|
|
2012-05-29 15:04:22 -07:00
|
|
|
let shape = shape_of(ccx, key);
|
2011-08-04 11:25:09 -07:00
|
|
|
let shape_tables =
|
|
|
|
llvm::LLVMConstPointerCast(ccx.shape_cx.llshapetables,
|
|
|
|
T_ptr(T_i8()));
|
|
|
|
|
|
|
|
let tydesc =
|
2011-07-14 15:19:17 -04:00
|
|
|
C_named_struct(ccx.tydesc_type,
|
2011-08-19 15:16:48 -07:00
|
|
|
[C_null(T_ptr(T_ptr(ccx.tydesc_type))),
|
|
|
|
ti.size, // size
|
|
|
|
ti.align, // align
|
2011-08-19 10:24:13 +02:00
|
|
|
take_glue, // take_glue
|
2011-08-19 15:16:48 -07:00
|
|
|
drop_glue, // drop_glue
|
|
|
|
free_glue, // free_glue
|
2012-05-14 17:57:39 -07:00
|
|
|
visit_glue, // visit_glue
|
2012-06-08 12:54:23 -07:00
|
|
|
C_int(ccx, 0), // ununsed
|
|
|
|
C_int(ccx, 0), // ununsed
|
|
|
|
C_int(ccx, 0), // ununsed
|
|
|
|
C_int(ccx, 0), // ununsed
|
2011-08-19 15:16:48 -07:00
|
|
|
C_shape(ccx, shape), // shape
|
|
|
|
shape_tables, // shape_tables
|
2012-06-08 12:54:23 -07:00
|
|
|
C_int(ccx, 0), // ununsed
|
|
|
|
C_int(ccx, 0)]); // unused
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
let gvar = ti.tydesc;
|
2011-05-12 15:42:12 -07:00
|
|
|
llvm::LLVMSetInitializer(gvar, tydesc);
|
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(gvar, lib::llvm::InternalLinkage);
|
2011-10-21 12:21:27 +02:00
|
|
|
};
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn make_take_glue(bcx: block, v: ValueRef, t: ty::t) {
|
|
|
|
let _icx = bcx.insn_ctxt("make_take_glue");
|
2012-02-10 11:32:03 +01:00
|
|
|
// NB: v is a *pointer* to type t here, not a direct value.
|
2012-03-23 14:45:47 +01:00
|
|
|
let bcx = alt ty::get(t).struct {
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) | ty::ty_estr(ty::vstore_box) {
|
2012-03-23 14:45:47 +01:00
|
|
|
incr_refcnt_of_boxed(bcx, Load(bcx, v)); bcx
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
|
|
|
ty::ty_uniq(_) {
|
2012-03-23 14:45:47 +01:00
|
|
|
let {bcx, val} = uniq::duplicate(bcx, Load(bcx, v), t);
|
|
|
|
Store(bcx, val, v);
|
|
|
|
bcx
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_vec(_) | ty::ty_str |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) {
|
2012-04-19 15:42:02 -07:00
|
|
|
let {bcx, val} = tvec::duplicate_uniq(bcx, Load(bcx, v), t);
|
2012-03-23 14:45:47 +01:00
|
|
|
Store(bcx, val, v);
|
|
|
|
bcx
|
2011-12-14 07:31:12 -08:00
|
|
|
}
|
2012-01-26 10:29:47 +01:00
|
|
|
ty::ty_fn(_) {
|
2012-01-27 13:17:06 +01:00
|
|
|
closure::make_fn_glue(bcx, v, t, take_ty)
|
2011-12-14 07:31:12 -08:00
|
|
|
}
|
2012-02-10 11:32:03 +01:00
|
|
|
ty::ty_iface(_, _) {
|
2012-05-03 22:31:38 -07:00
|
|
|
let box = Load(bcx, GEPi(bcx, v, [0u, 1u]));
|
2012-03-23 14:45:47 +01:00
|
|
|
incr_refcnt_of_boxed(bcx, box);
|
|
|
|
bcx
|
2012-02-10 11:32:03 +01:00
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
2012-01-27 13:17:06 +01:00
|
|
|
closure::make_opaque_cbox_take_glue(bcx, ck, v)
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2012-02-03 15:15:28 +01:00
|
|
|
_ if ty::type_is_structural(t) {
|
2011-12-14 07:31:12 -08:00
|
|
|
iter_structural_ty(bcx, v, t, take_ty)
|
2011-12-13 21:44:57 -08:00
|
|
|
}
|
2011-12-14 07:31:12 -08:00
|
|
|
_ { bcx }
|
|
|
|
};
|
2011-08-17 13:58:49 -07:00
|
|
|
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn incr_refcnt_of_boxed(cx: block, box_ptr: ValueRef) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("incr_refcnt_of_boxed");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-02-01 18:52:08 -08:00
|
|
|
maybe_validate_box(cx, box_ptr);
|
2012-05-03 22:31:38 -07:00
|
|
|
let rc_ptr = GEPi(cx, box_ptr, [0u, abi::box_field_refcnt]);
|
2011-08-30 09:59:30 +02:00
|
|
|
let rc = Load(cx, rc_ptr);
|
2012-03-15 09:47:03 -04:00
|
|
|
let rc = Add(cx, rc, C_int(ccx, 1));
|
2011-09-02 12:21:01 -07:00
|
|
|
Store(cx, rc, rc_ptr);
|
2010-12-10 16:13:52 -08:00
|
|
|
}
|
|
|
|
|
2012-05-14 17:57:39 -07:00
|
|
|
fn make_visit_glue(bcx: block, v: ValueRef, t: ty::t) {
|
|
|
|
let _icx = bcx.insn_ctxt("make_visit_glue");
|
|
|
|
let mut bcx = bcx;
|
2012-06-10 00:49:59 -07:00
|
|
|
assert bcx.ccx().tcx.intrinsic_ifaces.contains_key(@"ty_visitor");
|
|
|
|
let (iid, ty) = bcx.ccx().tcx.intrinsic_ifaces.get(@"ty_visitor");
|
2012-05-16 18:24:00 -07:00
|
|
|
let v = PointerCast(bcx, v, T_ptr(type_of::type_of(bcx.ccx(), ty)));
|
2012-05-28 13:19:31 -07:00
|
|
|
bcx = reflect::emit_calls_to_iface_visit_ty(bcx, t, v, iid);
|
2012-05-14 17:57:39 -07:00
|
|
|
build_return(bcx);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn make_free_glue(bcx: block, v: ValueRef, t: ty::t) {
|
2011-10-10 09:51:09 +02:00
|
|
|
// v is a pointer to the actual box component of the type here. The
|
|
|
|
// ValueRef will have the wrong type here (make_generic_glue is casting
|
|
|
|
// everything to a pointer to the type that the glue acts on).
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("make_free_glue");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-03 15:15:28 +01:00
|
|
|
let bcx = alt ty::get(t).struct {
|
2011-10-10 09:51:09 +02:00
|
|
|
ty::ty_box(body_mt) {
|
2012-02-07 11:25:04 +01:00
|
|
|
let v = PointerCast(bcx, v, type_of(ccx, t));
|
2012-05-03 22:31:38 -07:00
|
|
|
let body = GEPi(bcx, v, [0u, abi::box_field_body]);
|
2012-02-07 11:25:04 +01:00
|
|
|
let bcx = drop_ty(bcx, body, body_mt.ty);
|
|
|
|
trans_free(bcx, v)
|
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
|
|
|
|
ty::ty_estr(ty::vstore_box) {
|
|
|
|
let v = PointerCast(bcx, v, type_of(ccx, t));
|
|
|
|
trans_free(bcx, v)
|
|
|
|
}
|
|
|
|
|
2012-02-07 11:25:04 +01:00
|
|
|
ty::ty_opaque_box {
|
|
|
|
let v = PointerCast(bcx, v, type_of(ccx, t));
|
2012-05-03 22:31:38 -07:00
|
|
|
let td = Load(bcx, GEPi(bcx, v, [0u, abi::box_field_tydesc]));
|
|
|
|
let valptr = GEPi(bcx, v, [0u, abi::box_field_body]);
|
2012-02-07 11:25:04 +01:00
|
|
|
call_tydesc_glue_full(bcx, valptr, td, abi::tydesc_field_drop_glue,
|
|
|
|
none);
|
|
|
|
trans_free(bcx, v)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
|
|
|
ty::ty_uniq(content_mt) {
|
2012-02-07 11:25:04 +01:00
|
|
|
let v = PointerCast(bcx, v, type_of(ccx, t));
|
2012-01-27 13:17:06 +01:00
|
|
|
uniq::make_free_glue(bcx, v, t)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) |
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_vec(_) | ty::ty_str {
|
2012-02-07 11:25:04 +01:00
|
|
|
tvec::make_free_glue(bcx, PointerCast(bcx, v, type_of(ccx, t)), t)
|
2011-10-10 13:32:50 +02:00
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_evec(_, _) {
|
|
|
|
bcx.sess().unimpl("trans::base::make_free_glue on other evec");
|
|
|
|
}
|
2012-01-26 10:29:47 +01:00
|
|
|
ty::ty_fn(_) {
|
2012-01-27 13:17:06 +01:00
|
|
|
closure::make_fn_glue(bcx, v, t, free_ty)
|
2011-12-15 11:06:48 -08:00
|
|
|
}
|
2012-01-05 16:19:12 -08:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
2012-01-27 13:17:06 +01:00
|
|
|
closure::make_opaque_cbox_free_glue(bcx, ck, v)
|
2011-10-10 09:51:09 +02:00
|
|
|
}
|
2012-06-12 16:25:09 -07:00
|
|
|
ty::ty_class(did,substs) {
|
|
|
|
// Call the dtor if there is one
|
|
|
|
option::map_default(ty::ty_dtor(bcx.tcx(), did), bcx) {|dt_id|
|
|
|
|
trans_class_drop(bcx, v, dt_id, did, substs)
|
|
|
|
}
|
|
|
|
}
|
2011-10-10 09:51:09 +02:00
|
|
|
_ { bcx }
|
|
|
|
};
|
2011-08-30 13:50:58 +02:00
|
|
|
build_return(bcx);
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
|
2012-05-22 21:44:28 -04:00
|
|
|
fn trans_class_drop(bcx: block, v0: ValueRef, dtor_did: ast::def_id,
|
|
|
|
class_did: ast::def_id,
|
|
|
|
substs: ty::substs) -> block {
|
|
|
|
let drop_flag = GEPi(bcx, v0, [0u, 0u]);
|
|
|
|
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|cx|
|
|
|
|
let mut bcx = cx;
|
|
|
|
// We have to cast v0
|
|
|
|
let classptr = GEPi(bcx, v0, [0u, 1u]);
|
|
|
|
// Find and call the actual destructor
|
|
|
|
let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, substs.tps);
|
|
|
|
// The second argument is the "self" argument for drop
|
|
|
|
let params = lib::llvm::fn_ty_param_tys
|
|
|
|
(llvm::LLVMGetElementType
|
|
|
|
(llvm::LLVMTypeOf(dtor_addr)));
|
|
|
|
// Class dtors have no explicit args, so the params should just consist
|
|
|
|
// of the output pointer and the environment (self)
|
|
|
|
assert(params.len() == 2u);
|
|
|
|
let self_arg = PointerCast(bcx, v0, params[1u]);
|
|
|
|
let args = [bcx.fcx.llretptr, self_arg];
|
|
|
|
Call(bcx, dtor_addr, args);
|
|
|
|
// Drop the fields
|
2012-06-08 14:37:55 -07:00
|
|
|
for vec::eachi(ty::class_items_as_mutable_fields(bcx.tcx(), class_did,
|
|
|
|
substs))
|
2012-05-22 21:44:28 -04:00
|
|
|
{|i, fld|
|
|
|
|
let llfld_a = GEPi(bcx, classptr, [0u, i]);
|
|
|
|
bcx = drop_ty(bcx, llfld_a, fld.mt.ty);
|
|
|
|
}
|
|
|
|
Store(bcx, C_u8(0u), drop_flag);
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn make_drop_glue(bcx: block, v0: ValueRef, t: ty::t) {
|
2011-05-18 17:28:08 -07:00
|
|
|
// NB: v0 is an *alias* of type t here, not a direct value.
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("make_drop_glue");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-03 15:15:28 +01:00
|
|
|
let bcx = alt ty::get(t).struct {
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
2012-04-16 16:17:51 -07:00
|
|
|
ty::ty_estr(ty::vstore_box) | ty::ty_evec(_, ty::vstore_box) {
|
2012-02-03 15:15:28 +01:00
|
|
|
decr_refcnt_maybe_free(bcx, Load(bcx, v0), t)
|
|
|
|
}
|
2012-04-16 16:17:51 -07:00
|
|
|
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) | ty::ty_estr(ty::vstore_uniq) {
|
2012-02-03 15:15:28 +01:00
|
|
|
free_ty(bcx, Load(bcx, v0), t)
|
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ty::ty_res(did, inner, substs) {
|
|
|
|
trans_res_drop(bcx, v0, did, inner, substs.tps)
|
2012-02-03 15:15:28 +01:00
|
|
|
}
|
2012-05-15 17:59:55 -07:00
|
|
|
ty::ty_class(did, substs) {
|
|
|
|
let tcx = bcx.tcx();
|
|
|
|
alt ty::ty_dtor(tcx, did) {
|
|
|
|
some(dtor) {
|
2012-05-22 21:44:28 -04:00
|
|
|
trans_class_drop(bcx, v0, dtor, did, substs)
|
2012-05-15 17:59:55 -07:00
|
|
|
}
|
|
|
|
none {
|
|
|
|
// No dtor? Just the default case
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-02-03 15:15:28 +01:00
|
|
|
ty::ty_fn(_) {
|
|
|
|
closure::make_fn_glue(bcx, v0, t, drop_ty)
|
|
|
|
}
|
2012-02-10 11:32:03 +01:00
|
|
|
ty::ty_iface(_, _) {
|
2012-05-03 22:31:38 -07:00
|
|
|
let box = Load(bcx, GEPi(bcx, v0, [0u, 1u]));
|
2012-02-10 11:32:03 +01:00
|
|
|
decr_refcnt_maybe_free(bcx, box, ty::mk_opaque_box(ccx.tcx))
|
|
|
|
}
|
2012-02-03 15:15:28 +01:00
|
|
|
ty::ty_opaque_closure_ptr(ck) {
|
|
|
|
closure::make_opaque_cbox_drop_glue(bcx, ck, v0)
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
if ty::type_needs_drop(ccx.tcx, t) &&
|
|
|
|
ty::type_is_structural(t) {
|
|
|
|
iter_structural_ty(bcx, v0, t, drop_ty)
|
|
|
|
} else { bcx }
|
|
|
|
}
|
|
|
|
};
|
2011-08-30 13:50:58 +02:00
|
|
|
build_return(bcx);
|
2010-12-10 15:02:23 -08:00
|
|
|
}
|
|
|
|
|
2012-03-08 21:16:04 +01:00
|
|
|
fn get_res_dtor(ccx: @crate_ctxt, did: ast::def_id, substs: [ty::t])
|
|
|
|
-> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_res_dtor");
|
2012-04-18 13:46:21 +02:00
|
|
|
if (substs.len() > 0u) {
|
|
|
|
let did = if did.crate != ast::local_crate {
|
|
|
|
maybe_instantiate_inline(ccx, did)
|
|
|
|
} else { did };
|
|
|
|
assert did.crate == ast::local_crate;
|
|
|
|
monomorphic_fn(ccx, did, substs, none, none).val
|
|
|
|
} else if did.crate == ast::local_crate {
|
|
|
|
get_item_val(ccx, did.node)
|
|
|
|
} else {
|
2012-05-24 23:44:58 -07:00
|
|
|
let fty = ty::mk_fn(ccx.tcx, {purity: ast::impure_fn,
|
|
|
|
proto: ast::proto_bare,
|
2012-04-18 13:46:21 +02:00
|
|
|
inputs: [{mode: ast::expl(ast::by_ref),
|
|
|
|
ty: ty::mk_nil_ptr(ccx.tcx)}],
|
|
|
|
output: ty::mk_nil(ccx.tcx),
|
|
|
|
ret_style: ast::return_val,
|
|
|
|
constraints: []});
|
|
|
|
trans_external_path(ccx, did, fty)
|
|
|
|
}
|
2012-03-08 21:16:04 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_res_drop(bcx: block, rs: ValueRef, did: ast::def_id,
|
|
|
|
inner_t: ty::t, tps: [ty::t]) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_res_drop");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-04-18 21:26:25 -07:00
|
|
|
let inner_t_s = ty::subst_tps(ccx.tcx, tps, inner_t);
|
2012-02-17 13:17:40 +01:00
|
|
|
|
2012-05-03 22:31:38 -07:00
|
|
|
let drop_flag = GEPi(bcx, rs, [0u, 0u]);
|
2012-02-17 13:17:40 +01:00
|
|
|
with_cond(bcx, IsNotNull(bcx, Load(bcx, drop_flag))) {|bcx|
|
2012-05-03 22:31:38 -07:00
|
|
|
let valptr = GEPi(bcx, rs, [0u, 1u]);
|
2012-02-17 13:17:40 +01:00
|
|
|
// Find and call the actual destructor.
|
2012-03-08 21:16:04 +01:00
|
|
|
let dtor_addr = get_res_dtor(ccx, did, tps);
|
2012-02-17 13:17:40 +01:00
|
|
|
let args = [bcx.fcx.llretptr, null_env_ptr(bcx)];
|
|
|
|
// Kludge to work around the fact that we know the precise type of the
|
2012-03-08 21:16:04 +01:00
|
|
|
// value here, but the dtor expects a type that might have opaque
|
|
|
|
// boxes and such.
|
2012-02-17 13:17:40 +01:00
|
|
|
let val_llty = lib::llvm::fn_ty_param_tys
|
|
|
|
(llvm::LLVMGetElementType
|
|
|
|
(llvm::LLVMTypeOf(dtor_addr)))[args.len()];
|
|
|
|
let val_cast = BitCast(bcx, valptr, val_llty);
|
|
|
|
Call(bcx, dtor_addr, args + [val_cast]);
|
|
|
|
|
2012-03-12 09:26:54 +01:00
|
|
|
let bcx = drop_ty(bcx, valptr, inner_t_s);
|
2012-02-21 14:51:17 +01:00
|
|
|
Store(bcx, C_u8(0u), drop_flag);
|
2012-02-17 13:17:40 +01:00
|
|
|
bcx
|
|
|
|
}
|
2011-06-28 16:14:01 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn maybe_validate_box(_cx: block, _box_ptr: ValueRef) {
|
2012-02-01 18:52:08 -08:00
|
|
|
// Uncomment this when debugging annoying use-after-free
|
|
|
|
// bugs. But do not commit with this uncommented! Big performance hit.
|
|
|
|
|
|
|
|
// let cx = _cx, box_ptr = _box_ptr;
|
2012-02-21 14:20:18 +01:00
|
|
|
// let ccx = cx.ccx();
|
2012-02-01 18:52:08 -08:00
|
|
|
// warn_not_to_commit(ccx, "validate_box() is uncommented");
|
|
|
|
// let raw_box_ptr = PointerCast(cx, box_ptr, T_ptr(T_i8()));
|
|
|
|
// Call(cx, ccx.upcalls.validate_box, [raw_box_ptr]);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn decr_refcnt_maybe_free(bcx: block, box_ptr: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("decr_refcnt_maybe_free");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-17 13:17:40 +01:00
|
|
|
maybe_validate_box(bcx, box_ptr);
|
2012-02-01 18:52:08 -08:00
|
|
|
|
2012-02-10 11:32:03 +01:00
|
|
|
let llbox_ty = T_opaque_box_ptr(ccx);
|
2012-02-17 13:17:40 +01:00
|
|
|
let box_ptr = PointerCast(bcx, box_ptr, llbox_ty);
|
|
|
|
with_cond(bcx, IsNotNull(bcx, box_ptr)) {|bcx|
|
2012-05-03 22:31:38 -07:00
|
|
|
let rc_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_refcnt]);
|
2012-02-17 13:17:40 +01:00
|
|
|
let rc = Sub(bcx, Load(bcx, rc_ptr), C_int(ccx, 1));
|
|
|
|
Store(bcx, rc, rc_ptr);
|
|
|
|
let zero_test = ICmp(bcx, lib::llvm::IntEQ, C_int(ccx, 0), rc);
|
|
|
|
with_cond(bcx, zero_test) {|bcx| free_ty(bcx, box_ptr, t)}
|
|
|
|
}
|
2010-10-01 18:25:42 -07:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
// Structural comparison: a rather involved form of glue.
|
2012-03-14 17:31:16 -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-03-14 15:10:34 -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
|
|
|
|
2011-06-02 16:23:52 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn compare_scalar_types(cx: block, lhs: ValueRef, rhs: ValueRef,
|
2011-10-27 22:01:30 -07:00
|
|
|
t: ty::t, op: ast::binop) -> result {
|
|
|
|
let f = bind compare_scalar_values(cx, lhs, rhs, _, op);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t).struct {
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_nil { ret rslt(cx, f(nil_type)); }
|
|
|
|
ty::ty_bool | ty::ty_ptr(_) { ret rslt(cx, f(unsigned_int)); }
|
2011-12-07 21:06:12 +01:00
|
|
|
ty::ty_int(_) { ret rslt(cx, f(signed_int)); }
|
|
|
|
ty::ty_uint(_) { ret rslt(cx, f(unsigned_int)); }
|
|
|
|
ty::ty_float(_) { ret rslt(cx, f(floating_point)); }
|
2012-01-18 22:37:22 -08:00
|
|
|
ty::ty_type {
|
2011-09-26 13:21:47 +02:00
|
|
|
ret rslt(trans_fail(cx, none,
|
|
|
|
"attempt to compare values of type type"),
|
|
|
|
C_nil());
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
// Should never get here, because t is scalar.
|
2012-02-21 14:20:18 +01:00
|
|
|
cx.sess().bug("non-scalar type passed to \
|
2011-07-22 23:56:02 -07:00
|
|
|
compare_scalar_types");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
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-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("compare_scalar_values");
|
2012-02-17 13:17:40 +01:00
|
|
|
fn die_(cx: block) -> ! {
|
2012-02-21 14:20:18 +01:00
|
|
|
cx.tcx().sess.bug("compare_scalar_values: must be a\
|
2012-01-30 21:00:57 -08:00
|
|
|
comparison operator");
|
|
|
|
}
|
|
|
|
let die = bind die_(cx);
|
2011-10-28 14:20:10 -07:00
|
|
|
alt nt {
|
2012-01-18 22:37:22 -08: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.
|
2011-10-27 22:01:30 -07:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq | ast::le | ast::ge { ret C_bool(true); }
|
|
|
|
ast::ne | ast::lt | ast::gt { ret C_bool(false); }
|
2012-01-30 21:00:57 -08:00
|
|
|
// refinements would be nice
|
|
|
|
_ { die(); }
|
2011-10-27 22:01:30 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
floating_point {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-02-01 11:04:56 +01: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 }
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { die(); }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret FCmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
signed_int {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-02-01 11:04:56 +01: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 }
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { die(); }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret ICmp(cx, cmp, lhs, rhs);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
unsigned_int {
|
2011-10-28 14:20:10 -07:00
|
|
|
let cmp = alt op {
|
2012-02-01 11:04:56 +01: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 }
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { die(); }
|
2011-10-28 14:20:10 -07:00
|
|
|
};
|
|
|
|
ret 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-05-03 22:31:38 -07:00
|
|
|
fn load_inbounds(cx: block, p: ValueRef, idxs: [uint]) -> ValueRef {
|
2011-11-10 09:14:53 -08:00
|
|
|
ret Load(cx, GEPi(cx, p, idxs));
|
2011-07-05 14:19:19 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn store_inbounds(cx: block, v: ValueRef, p: ValueRef,
|
2012-05-03 22:31:38 -07:00
|
|
|
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-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("iter_structural_ty");
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn iter_variant(cx: block, a_tup: ValueRef,
|
2011-09-12 11:27:30 +02:00
|
|
|
variant: ty::variant_info, tps: [ty::t], tid: ast::def_id,
|
2012-02-17 13:17:40 +01:00
|
|
|
f: val_and_ty_fn) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("iter_variant");
|
2012-02-14 09:10:47 +01:00
|
|
|
if variant.args.len() == 0u { ret 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-02-03 15:15:28 +01:00
|
|
|
alt ty::get(fn_ty).struct {
|
2011-12-23 16:09:52 +01:00
|
|
|
ty::ty_fn({inputs: args, _}) {
|
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-03-27 15:14:12 +02:00
|
|
|
for vec::each(args) {|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-02-21 14:20:18 +01:00
|
|
|
_ { cx.tcx().sess.bug("iter_variant: not a function type"); }
|
2011-07-01 12:36:49 +02:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret 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-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t).struct {
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_rec(fields) {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::eachi(fields) {|i, fld|
|
2012-05-03 22:31:38 -07:00
|
|
|
let llfld_a = GEPi(cx, av, [0u, i]);
|
2012-03-12 09:26:54 +01:00
|
|
|
cx = f(cx, llfld_a, fld.mt.ty);
|
2011-06-10 19:35:59 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_estr(ty::vstore_fixed(n)) |
|
|
|
|
ty::ty_evec(_, ty::vstore_fixed(n)) {
|
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
|
|
|
}
|
2011-08-15 11:40:26 +02:00
|
|
|
ty::ty_tup(args) {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::eachi(args) {|i, arg|
|
2012-05-03 22:31:38 -07:00
|
|
|
let llfld_a = GEPi(cx, av, [0u, i]);
|
2012-03-12 09:26:54 +01:00
|
|
|
cx = f(cx, llfld_a, arg);
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ty::ty_res(_, inner, substs) {
|
2012-02-21 14:20:18 +01:00
|
|
|
let tcx = cx.tcx();
|
2012-04-18 21:26:25 -07:00
|
|
|
let inner1 = ty::subst(tcx, substs, inner);
|
2012-05-03 22:31:38 -07:00
|
|
|
let llfld_a = GEPi(cx, av, [0u, 1u]);
|
2012-03-12 09:26:54 +01:00
|
|
|
ret f(cx, llfld_a, inner1);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-04-18 21:26:25 -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-04-18 21:26:25 -07:00
|
|
|
ret iter_variant(cx, av, variants[0],
|
|
|
|
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-05-03 22:31:38 -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-02-17 13:17:40 +01: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-02-17 13:17:40 +01:00
|
|
|
let next_cx = sub_block(cx, "enum-iter-next");
|
2012-03-27 15:14:12 +02: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-01-19 14:24:03 -08: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-04-18 21:26:25 -07:00
|
|
|
iter_variant(variant_cx, llunion_a_ptr, variant,
|
|
|
|
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
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret next_cx;
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ty::ty_class(did, substs) {
|
2012-06-08 14:37:55 -07:00
|
|
|
for vec::eachi(ty::class_items_as_mutable_fields(cx.tcx(), did,
|
|
|
|
substs))
|
2012-05-03 22:31:38 -07:00
|
|
|
{|i, fld|
|
2012-05-15 17:59:55 -07:00
|
|
|
let llfld_a = GEPi(cx, av, [0u, i]);
|
|
|
|
cx = f(cx, llfld_a, fld.mt.ty);
|
2012-05-03 22:31:38 -07:00
|
|
|
}
|
2012-03-03 17:49:23 -08:00
|
|
|
}
|
2012-02-21 14:20:18 +01:00
|
|
|
_ { cx.sess().unimpl("type in iter_structural_ty"); }
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn lazily_emit_all_tydesc_glue(ccx: @crate_ctxt,
|
2012-01-31 17:05:20 -08:00
|
|
|
static_ti: option<@tydesc_info>) {
|
2012-02-07 11:25:04 +01:00
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_take_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_drop_glue, static_ti);
|
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_free_glue, static_ti);
|
2012-05-16 18:24:00 -07:00
|
|
|
lazily_emit_tydesc_glue(ccx, abi::tydesc_field_visit_glue, static_ti);
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
|
2012-05-03 22:31:38 -07:00
|
|
|
fn lazily_emit_tydesc_glue(ccx: @crate_ctxt, field: uint,
|
2012-01-31 17:05:20 -08:00
|
|
|
static_ti: option<@tydesc_info>) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("lazily_emit_tydesc_glue");
|
2011-07-27 14:19:39 +02:00
|
|
|
alt static_ti {
|
2012-01-18 22:37:22 -08:00
|
|
|
none { }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(ti) {
|
2011-08-19 10:24:13 +02:00
|
|
|
if field == abi::tydesc_field_take_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.take_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue TAKE %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2012-02-03 09:53:37 +01:00
|
|
|
let glue_fn = declare_generic_glue
|
|
|
|
(ccx, ti.ty, T_glue_fn(ccx), "take");
|
|
|
|
ti.take_glue = some(glue_fn);
|
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn,
|
2012-03-11 12:06:05 +01:00
|
|
|
make_take_glue, "take");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue TAKE %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.drop_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue DROP %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
let glue_fn =
|
2012-02-03 09:53:37 +01:00
|
|
|
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "drop");
|
|
|
|
ti.drop_glue = some(glue_fn);
|
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn,
|
2012-03-11 12:06:05 +01:00
|
|
|
make_drop_glue, "drop");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue DROP %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
2011-09-20 17:29:09 +02:00
|
|
|
alt ti.free_glue {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(_) { }
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("+++ lazily_emit_tydesc_glue FREE %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
let glue_fn =
|
2012-02-03 09:53:37 +01:00
|
|
|
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "free");
|
|
|
|
ti.free_glue = some(glue_fn);
|
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn,
|
2012-03-11 12:06:05 +01:00
|
|
|
make_free_glue, "free");
|
2011-12-22 16:13:40 -08:00
|
|
|
#debug("--- lazily_emit_tydesc_glue FREE %s",
|
2012-02-07 11:25:04 +01:00
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
2012-05-14 17:57:39 -07:00
|
|
|
} else if field == abi::tydesc_field_visit_glue {
|
2012-06-06 19:38:47 -07:00
|
|
|
alt ti.visit_glue {
|
2012-05-14 17:57:39 -07:00
|
|
|
some(_) { }
|
|
|
|
none {
|
|
|
|
#debug("+++ lazily_emit_tydesc_glue VISIT %s",
|
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
let glue_fn =
|
|
|
|
declare_generic_glue(ccx, ti.ty, T_glue_fn(ccx), "visit");
|
|
|
|
ti.visit_glue = some(glue_fn);
|
|
|
|
make_generic_glue(ccx, ti.ty, glue_fn,
|
|
|
|
make_visit_glue, "visit");
|
|
|
|
#debug("--- lazily_emit_tydesc_glue VISIT %s",
|
|
|
|
ty_to_str(ccx.tcx, ti.ty));
|
|
|
|
}
|
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
2012-05-14 17:57:39 -07:00
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-05-12 15:42:12 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-12 14:55:44 -07:00
|
|
|
// See [Note-arg-mode]
|
|
|
|
fn call_tydesc_glue_full(++cx: block, v: ValueRef, tydesc: ValueRef,
|
2012-05-03 22:31:38 -07:00
|
|
|
field: uint, static_ti: option<@tydesc_info>) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("call_tydesc_glue_full");
|
2012-02-21 14:20:18 +01:00
|
|
|
lazily_emit_tydesc_glue(cx.ccx(), field, static_ti);
|
2012-02-28 10:38:02 +01:00
|
|
|
if cx.unreachable { ret; }
|
2011-06-27 15:38:04 -07:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut static_glue_fn = none;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt static_ti {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {/* no-op */ }
|
2011-07-27 14:19:39 +02:00
|
|
|
some(sti) {
|
2011-08-19 10:24:13 +02:00
|
|
|
if field == abi::tydesc_field_take_glue {
|
|
|
|
static_glue_fn = sti.take_glue;
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_drop_glue {
|
2011-06-27 15:38:04 -07:00
|
|
|
static_glue_fn = sti.drop_glue;
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if field == abi::tydesc_field_free_glue {
|
2011-06-27 15:38:04 -07:00
|
|
|
static_glue_fn = sti.free_glue;
|
2012-06-06 19:38:47 -07:00
|
|
|
} else if field == abi::tydesc_field_visit_glue {
|
|
|
|
static_glue_fn = sti.visit_glue;
|
2011-06-27 15:38:04 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-30 09:59:30 +02:00
|
|
|
let llrawptr = PointerCast(cx, v, T_ptr(T_i8()));
|
2012-03-15 09:47:03 -04:00
|
|
|
|
|
|
|
let llfn = {
|
|
|
|
alt static_glue_fn {
|
|
|
|
none {
|
2012-05-03 22:31:38 -07:00
|
|
|
let llfnptr = GEPi(cx, tydesc, [0u, field]);
|
2012-03-15 09:47:03 -04:00
|
|
|
Load(cx, llfnptr)
|
|
|
|
}
|
|
|
|
some(sgf) { sgf }
|
|
|
|
}
|
|
|
|
};
|
2011-06-27 15:38:04 -07:00
|
|
|
|
2011-10-20 11:56:45 +02:00
|
|
|
Call(cx, llfn, [C_null(T_ptr(T_nil())), C_null(T_ptr(T_nil())),
|
2012-04-02 15:21:26 -07:00
|
|
|
C_null(T_ptr(T_ptr(cx.ccx().tydesc_type))), llrawptr]);
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2012-06-12 14:55:44 -07:00
|
|
|
// See [Note-arg-mode]
|
|
|
|
fn call_tydesc_glue(++cx: block, v: ValueRef, t: ty::t, field: uint)
|
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("call_tydesc_glue");
|
2012-03-21 15:42:20 +01:00
|
|
|
let mut ti = none;
|
|
|
|
let td = get_tydesc(cx.ccx(), t, ti);
|
|
|
|
call_tydesc_glue_full(cx, v, td, field, ti);
|
|
|
|
ret cx;
|
2011-01-28 14:34:25 -08:00
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn call_cmp_glue(bcx: block, lhs: ValueRef, rhs: ValueRef, t: ty::t,
|
|
|
|
llop: ValueRef) -> ValueRef {
|
2011-04-19 15:22:57 -07:00
|
|
|
// We can't use call_tydesc_glue_full() and friends here because compare
|
|
|
|
// glue has a special signature.
|
2012-03-23 14:45:47 +01:00
|
|
|
let _icx = bcx.insn_ctxt("call_cmp_glue");
|
2011-09-02 15:12:27 -07:00
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
let lllhs = spill_if_immediate(bcx, lhs, t);
|
|
|
|
let llrhs = spill_if_immediate(bcx, rhs, t);
|
2011-09-02 15:12:27 -07:00
|
|
|
|
|
|
|
let llrawlhsptr = BitCast(bcx, lllhs, T_ptr(T_i8()));
|
|
|
|
let llrawrhsptr = BitCast(bcx, llrhs, T_ptr(T_i8()));
|
2012-03-21 15:42:20 +01:00
|
|
|
let lltydesc = get_tydesc_simple(bcx.ccx(), t);
|
|
|
|
let lltydescs =
|
2012-05-03 22:31:38 -07:00
|
|
|
Load(bcx, GEPi(bcx, lltydesc, [0u, abi::tydesc_field_first_param]));
|
2011-06-27 18:35:01 -07:00
|
|
|
|
2012-02-21 14:20:18 +01:00
|
|
|
let llfn = bcx.ccx().upcalls.cmp_type;
|
2011-06-27 18:35:01 -07:00
|
|
|
|
2011-09-02 15:12:27 -07:00
|
|
|
let llcmpresultptr = alloca(bcx, T_i1());
|
2011-10-20 11:56:45 +02:00
|
|
|
Call(bcx, llfn, [llcmpresultptr, lltydesc, lltydescs,
|
2011-10-20 11:42:40 +02:00
|
|
|
llrawlhsptr, llrawrhsptr, llop]);
|
2012-03-23 14:45:47 +01:00
|
|
|
ret Load(bcx, llcmpresultptr);
|
2011-04-19 15:22:57 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn take_ty(cx: block, v: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("take_ty");
|
2012-02-21 14:20:18 +01:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
2011-08-19 10:24:13 +02:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_take_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn drop_ty(cx: block, v: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("drop_ty");
|
2012-02-21 14:20:18 +01:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
2011-05-20 14:57:52 -07:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_drop_glue);
|
2010-12-17 18:20:10 -08:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn drop_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("drop_ty_immediate");
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t).struct {
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_uniq(_) | ty::ty_vec(_) | ty::ty_str |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) |
|
|
|
|
ty::ty_estr(ty::vstore_uniq) {
|
|
|
|
free_ty(bcx, v, t)
|
|
|
|
}
|
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) |
|
|
|
|
ty::ty_estr(ty::vstore_box) {
|
2012-02-07 11:25:04 +01:00
|
|
|
decr_refcnt_maybe_free(bcx, v, t)
|
|
|
|
}
|
2012-02-21 14:20:18 +01:00
|
|
|
_ { bcx.tcx().sess.bug("drop_ty_immediate: non-box ty"); }
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn take_ty_immediate(bcx: block, v: ValueRef, t: ty::t) -> result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("take_ty_immediate");
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t).struct {
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_box(_) | ty::ty_opaque_box |
|
|
|
|
ty::ty_evec(_, ty::vstore_box) |
|
|
|
|
ty::ty_estr(ty::vstore_box) {
|
2012-03-23 14:45:47 +01:00
|
|
|
incr_refcnt_of_boxed(bcx, v);
|
|
|
|
rslt(bcx, v)
|
2012-01-07 22:44:14 +01:00
|
|
|
}
|
2011-10-10 10:58:53 +02:00
|
|
|
ty::ty_uniq(_) {
|
2012-01-27 13:17:06 +01:00
|
|
|
uniq::duplicate(bcx, v, t)
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
2012-04-09 17:32:49 -07:00
|
|
|
ty::ty_str | ty::ty_vec(_) |
|
|
|
|
ty::ty_evec(_, ty::vstore_uniq) |
|
|
|
|
ty::ty_estr(ty::vstore_uniq) {
|
2012-04-19 15:42:02 -07:00
|
|
|
tvec::duplicate_uniq(bcx, v, t)
|
2012-04-09 17:32:49 -07:00
|
|
|
}
|
2012-01-07 22:44:14 +01:00
|
|
|
_ { rslt(bcx, v) }
|
2011-10-10 10:58:53 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn free_ty(cx: block, v: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("free_ty");
|
2012-02-21 14:20:18 +01:00
|
|
|
if ty::type_needs_drop(cx.tcx(), t) {
|
2011-05-20 14:57:52 -07:00
|
|
|
ret call_tydesc_glue(cx, v, t, abi::tydesc_field_free_glue);
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
2011-08-30 13:50:58 +02:00
|
|
|
ret cx;
|
2011-05-18 17:28:08 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn call_memmove(cx: block, dst: ValueRef, src: ValueRef,
|
2012-03-23 14:45:47 +01:00
|
|
|
n_bytes: ValueRef) {
|
2012-02-21 14:51:17 +01:00
|
|
|
// FIXME: 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
|
2012-06-07 14:37:36 -07:00
|
|
|
// works). (Related to #1645, I think?)
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("call_memmove");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-01-12 17:59:49 +01:00
|
|
|
let key = alt ccx.sess.targ_cfg.arch {
|
2012-01-19 01:03:57 -08:00
|
|
|
session::arch_x86 | session::arch_arm { "llvm.memmove.p0i8.p0i8.i32" }
|
|
|
|
session::arch_x86_64 { "llvm.memmove.p0i8.p0i8.i64" }
|
2011-10-26 17:09:07 -07:00
|
|
|
};
|
2012-03-21 15:42:20 +01:00
|
|
|
let memmove = ccx.intrinsics.get(key);
|
2011-08-30 09:59:30 +02:00
|
|
|
let src_ptr = PointerCast(cx, src, T_ptr(T_i8()));
|
|
|
|
let dst_ptr = PointerCast(cx, dst, T_ptr(T_i8()));
|
2011-10-26 17:09:07 -07:00
|
|
|
let size = IntCast(cx, n_bytes, ccx.int_type);
|
|
|
|
let align = C_i32(1i32);
|
2011-07-27 14:19:39 +02:00
|
|
|
let volatile = C_bool(false);
|
2012-03-23 14:45:47 +01:00
|
|
|
Call(cx, memmove, [dst_ptr, src_ptr, size, align, volatile]);
|
2010-11-24 16:55:45 -08:00
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn memmove_ty(bcx: block, dst: ValueRef, src: ValueRef, t: ty::t) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("memmove_ty");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-03-12 10:05:15 +01:00
|
|
|
if ty::type_is_structural(t) {
|
|
|
|
let llsz = llsize_of(ccx, type_of(ccx, t));
|
2012-03-23 14:45:47 +01:00
|
|
|
call_memmove(bcx, dst, src, llsz);
|
|
|
|
} else {
|
|
|
|
Store(bcx, Load(bcx, src), dst);
|
2011-09-02 18:59:22 -07:00
|
|
|
}
|
2011-01-17 13:30:29 -08:00
|
|
|
}
|
|
|
|
|
2012-01-19 17:56:05 -08:00
|
|
|
enum copy_action { INIT, DROP_EXISTING, }
|
2011-06-10 13:39:13 -07:00
|
|
|
|
2011-08-22 12:38:58 +02:00
|
|
|
// These are the types that are passed by pointer.
|
2012-02-03 15:15:28 +01:00
|
|
|
fn type_is_structural_or_param(t: ty::t) -> bool {
|
|
|
|
if ty::type_is_structural(t) { ret true; }
|
|
|
|
alt ty::get(t).struct {
|
2011-08-22 12:38:58 +02:00
|
|
|
ty::ty_param(_, _) { ret true; }
|
|
|
|
_ { ret false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn copy_val(cx: block, action: copy_action, dst: ValueRef,
|
|
|
|
src: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("copy_val");
|
2011-09-27 20:20:51 +02:00
|
|
|
if action == DROP_EXISTING &&
|
2012-02-03 15:15:28 +01:00
|
|
|
(type_is_structural_or_param(t) ||
|
|
|
|
ty::type_is_unique(t)) {
|
2011-09-27 20:20:51 +02:00
|
|
|
let dstcmp = load_if_immediate(cx, dst, t);
|
2012-02-17 13:17:40 +01:00
|
|
|
let cast = PointerCast(cx, dstcmp, val_ty(src));
|
|
|
|
// Self-copy check
|
|
|
|
with_cond(cx, ICmp(cx, lib::llvm::IntNE, cast, src)) {|bcx|
|
|
|
|
copy_val_no_check(bcx, action, dst, src, t)
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
copy_val_no_check(cx, action, dst, src, t)
|
2011-08-22 12:38:58 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn copy_val_no_check(bcx: block, action: copy_action, dst: ValueRef,
|
|
|
|
src: ValueRef, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("copy_val_no_check");
|
2012-03-15 09:47:03 -04:00
|
|
|
let ccx = bcx.ccx();
|
|
|
|
let mut bcx = bcx;
|
2012-04-10 18:34:21 -07:00
|
|
|
if ty::type_is_scalar(t) || ty::type_is_slice(t) {
|
2011-10-10 13:32:50 +02:00
|
|
|
Store(bcx, src, dst);
|
|
|
|
ret bcx;
|
2011-09-07 12:10:37 -07:00
|
|
|
}
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_nil(t) || ty::type_is_bot(t) { ret bcx; }
|
|
|
|
if ty::type_is_boxed(t) || ty::type_is_vec(t) ||
|
|
|
|
ty::type_is_unique_box(t) {
|
2011-10-10 13:32:50 +02:00
|
|
|
if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(bcx, src, dst);
|
2011-09-07 12:10:37 -07:00
|
|
|
ret take_ty(bcx, dst, t);
|
|
|
|
}
|
2012-02-03 15:15:28 +01:00
|
|
|
if type_is_structural_or_param(t) {
|
2011-10-10 13:32:50 +02:00
|
|
|
if action == DROP_EXISTING { bcx = drop_ty(bcx, dst, t); }
|
2012-03-23 14:45:47 +01:00
|
|
|
memmove_ty(bcx, dst, src, t);
|
2011-08-30 13:50:58 +02:00
|
|
|
ret take_ty(bcx, dst, t);
|
2011-08-22 12:38:58 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
ccx.sess.bug("unexpected type in trans::copy_val_no_check: " +
|
|
|
|
ty_to_str(ccx.tcx, t));
|
2010-11-09 17:49:20 -08:00
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-05-31 14:36:08 -07:00
|
|
|
// This works like copy_val, except that it deinitializes the source.
|
|
|
|
// Since it needs to zero out the source, src also needs to be an lval.
|
|
|
|
// FIXME: We always zero out the source. Ideally we would detect the
|
|
|
|
// case where a variable is always deinitialized by block exit and thus
|
2012-06-07 14:37:36 -07:00
|
|
|
// doesn't need to be dropped. (Issue #839)
|
2012-02-17 13:17:40 +01:00
|
|
|
fn move_val(cx: block, action: copy_action, dst: ValueRef,
|
|
|
|
src: lval_result, t: ty::t) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("move_val");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut src_val = src.val;
|
|
|
|
let tcx = cx.tcx();
|
|
|
|
let mut cx = cx;
|
2012-04-10 18:34:21 -07:00
|
|
|
if ty::type_is_scalar(t) || ty::type_is_slice(t) {
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { src_val = Load(cx, src_val); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, src_val, dst);
|
2011-08-22 12:38:58 +02:00
|
|
|
ret cx;
|
2012-02-03 15:15:28 +01:00
|
|
|
} else if ty::type_is_nil(t) || ty::type_is_bot(t) {
|
2011-08-22 12:38:58 +02:00
|
|
|
ret cx;
|
2012-02-03 15:15:28 +01:00
|
|
|
} else if ty::type_is_boxed(t) || ty::type_is_unique(t) {
|
2011-10-07 11:20:51 +02:00
|
|
|
if src.kind == owned { src_val = Load(cx, src_val); }
|
2011-09-02 15:34:58 -07:00
|
|
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
2011-08-30 09:59:30 +02:00
|
|
|
Store(cx, src_val, dst);
|
2012-05-28 20:52:11 -07:00
|
|
|
if src.kind == owned { ret zero_mem(cx, src.val, t); }
|
2011-08-16 12:38:42 -07:00
|
|
|
// If we're here, it must be a temporary.
|
2011-11-18 15:10:14 +01:00
|
|
|
revoke_clean(cx, src_val);
|
|
|
|
ret cx;
|
2012-02-03 15:15:28 +01:00
|
|
|
} else if type_is_structural_or_param(t) {
|
2011-08-30 13:50:58 +02:00
|
|
|
if action == DROP_EXISTING { cx = drop_ty(cx, dst, t); }
|
2012-03-23 14:45:47 +01:00
|
|
|
memmove_ty(cx, dst, src_val, t);
|
2012-05-28 20:52:11 -07:00
|
|
|
if src.kind == owned { ret zero_mem(cx, src_val, t); }
|
2011-09-07 18:16:08 -07:00
|
|
|
// If we're here, it must be a temporary.
|
2011-11-18 15:10:14 +01:00
|
|
|
revoke_clean(cx, src_val);
|
|
|
|
ret cx;
|
2011-05-31 14:36:08 -07:00
|
|
|
}
|
2012-02-21 14:20:18 +01:00
|
|
|
cx.sess().bug("unexpected type in trans::move_val: " +
|
2012-02-21 14:25:53 +01:00
|
|
|
ty_to_str(tcx, t));
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn store_temp_expr(cx: block, action: copy_action, dst: ValueRef,
|
2011-11-18 15:10:14 +01:00
|
|
|
src: lval_result, t: ty::t, last_use: bool)
|
2012-02-17 13:17:40 +01:00
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_temp_expr");
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
// Lvals in memory are not temporaries. Copy them.
|
2011-11-18 15:10:14 +01:00
|
|
|
if src.kind != temporary && !last_use {
|
2012-01-29 21:33:08 -05:00
|
|
|
let v = if src.kind == owned {
|
|
|
|
load_if_immediate(cx, src.val, t)
|
|
|
|
} else {
|
|
|
|
src.val
|
|
|
|
};
|
2011-10-07 11:20:51 +02:00
|
|
|
ret copy_val(cx, action, dst, v, t);
|
2011-08-16 12:38:42 -07:00
|
|
|
}
|
|
|
|
ret move_val(cx, action, dst, src, t);
|
2011-05-31 14:36:08 -07:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_crate_lit(cx: @crate_ctxt, lit: ast::lit) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_crate_lit");
|
2011-07-27 14:19:39 +02:00
|
|
|
alt lit.node {
|
2011-12-07 21:06:12 +01:00
|
|
|
ast::lit_int(i, t) { C_integral(T_int_ty(cx, t), i as u64, True) }
|
|
|
|
ast::lit_uint(u, t) { C_integral(T_uint_ty(cx, t), u, False) }
|
2012-06-11 16:31:03 -07:00
|
|
|
ast::lit_int_unsuffixed(i, t) {
|
|
|
|
// FIXME (#1425): should we be using cx.fcx.infcx to figure out what
|
|
|
|
// to actually generate from this?
|
|
|
|
C_integral(T_int_ty(cx, t), i as u64, True)
|
|
|
|
}
|
2012-06-10 00:49:59 -07:00
|
|
|
ast::lit_float(fs, t) { C_floating(*fs, T_float_ty(cx, t)) }
|
2011-12-07 21:06:12 +01:00
|
|
|
ast::lit_bool(b) { C_bool(b) }
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::lit_nil { C_nil() }
|
2011-09-01 22:08:59 -07:00
|
|
|
ast::lit_str(s) {
|
2011-09-02 15:34:58 -07:00
|
|
|
cx.sess.span_unimpl(lit.span, "unique string in this context");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-07-14 11:47:20 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_lit(cx: block, lit: ast::lit, dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_lit");
|
2011-09-27 08:42:27 +02:00
|
|
|
if dest == ignore { ret cx; }
|
2011-07-27 14:19:39 +02:00
|
|
|
alt lit.node {
|
2012-04-16 16:17:51 -07:00
|
|
|
ast::lit_str(s) { tvec::trans_estr(cx, s, ast::vstore_uniq, dest) }
|
2011-09-27 08:42:27 +02:00
|
|
|
_ {
|
2012-04-09 17:32:49 -07:00
|
|
|
store_in_dest(cx, trans_crate_lit(cx.ccx(), lit), dest)
|
2011-09-27 08:42:27 +02:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_unary(bcx: block, op: ast::unop, e: @ast::expr,
|
|
|
|
un_expr: @ast::expr, dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_unary");
|
2012-01-26 12:26:14 +01:00
|
|
|
// Check for user-defined method call
|
2012-02-14 15:21:53 -08:00
|
|
|
alt bcx.ccx().maps.method_map.find(un_expr.id) {
|
2012-01-26 12:26:14 +01:00
|
|
|
some(origin) {
|
|
|
|
let callee_id = ast_util::op_expr_callee_id(un_expr);
|
2012-02-09 14:33:00 +01:00
|
|
|
let fty = node_id_type(bcx, callee_id);
|
2012-05-14 14:24:16 -07:00
|
|
|
ret trans_call_inner(
|
|
|
|
bcx, un_expr.info(), fty,
|
|
|
|
expr_ty(bcx, un_expr),
|
|
|
|
{|bcx| impl::trans_method_callee(bcx, callee_id, e, origin) },
|
|
|
|
arg_exprs([]), dest);
|
2012-01-26 12:26:14 +01:00
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
|
2011-10-05 11:26:27 +02:00
|
|
|
if dest == ignore { ret trans_expr(bcx, e, ignore); }
|
2012-02-02 12:37:17 +01:00
|
|
|
let e_ty = expr_ty(bcx, e);
|
2011-07-27 14:19:39 +02:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::not {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, e);
|
2011-09-27 13:19:55 +02:00
|
|
|
ret store_in_dest(bcx, Not(bcx, val), dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::neg {
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, e);
|
2012-02-03 15:15:28 +01:00
|
|
|
let neg = if ty::type_is_fp(e_ty) {
|
2011-09-27 13:19:55 +02:00
|
|
|
FNeg(bcx, val)
|
|
|
|
} else { Neg(bcx, val) };
|
|
|
|
ret store_in_dest(bcx, neg, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
ast::box(_) {
|
2012-03-23 14:45:47 +01:00
|
|
|
let mut {box, body} = malloc_boxed(bcx, e_ty);
|
2011-09-27 13:19:55 +02:00
|
|
|
add_clean_free(bcx, box, false);
|
2011-07-27 14:19:39 +02:00
|
|
|
// Cast the body type to the type of the value. This is needed to
|
2012-01-25 14:34:31 +01:00
|
|
|
// make enums work, since enums have a different LLVM type depending
|
2012-01-18 22:37:22 -08:00
|
|
|
// on whether they're boxed or not
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-03-12 10:05:15 +01:00
|
|
|
let llety = T_ptr(type_of(ccx, e_ty));
|
|
|
|
body = PointerCast(bcx, body, llety);
|
2012-03-23 14:45:47 +01:00
|
|
|
let bcx = trans_expr_save_in(bcx, e, body);
|
2011-09-27 13:19:55 +02:00
|
|
|
revoke_clean(bcx, box);
|
|
|
|
ret store_in_dest(bcx, box, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-20 18:06:47 -07:00
|
|
|
ast::uniq(_) {
|
2012-01-27 13:17:06 +01:00
|
|
|
ret uniq::trans_uniq(bcx, e, un_expr.id, dest);
|
2011-09-20 18:06:47 -07:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::deref {
|
2012-02-21 14:20:18 +01:00
|
|
|
bcx.sess().bug("deref expressions should have been \
|
2011-09-27 13:19:55 +02:00
|
|
|
translated using trans_lval(), not \
|
|
|
|
trans_unary()");
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-08 16:34:36 -08:00
|
|
|
fn trans_addr_of(cx: block, e: @ast::expr, dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_addr_of");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut {bcx, val, kind} = trans_temp_lval(cx, e);
|
2012-03-14 16:50:20 -07:00
|
|
|
let ety = expr_ty(cx, e);
|
|
|
|
let is_immediate = ty::type_is_immediate(ety);
|
|
|
|
if (kind == temporary && is_immediate) || kind == owned_imm {
|
2012-03-23 14:45:47 +01:00
|
|
|
val = do_spill(cx, val, ety);
|
2012-03-08 16:34:36 -08:00
|
|
|
}
|
|
|
|
ret store_in_dest(bcx, val, dest);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_compare(cx: block, op: ast::binop, lhs: ValueRef,
|
2011-08-19 15:16:48 -07:00
|
|
|
_lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t) -> result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_compare");
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_scalar(rhs_t) {
|
2011-10-27 22:01:30 -07:00
|
|
|
let rs = compare_scalar_types(cx, lhs, rhs, rhs_t, op);
|
|
|
|
ret rslt(rs.bcx, rs.val);
|
|
|
|
}
|
|
|
|
|
2011-04-19 15:22:57 -07:00
|
|
|
// Determine the operation we need.
|
2012-03-15 09:47:03 -04:00
|
|
|
let llop = {
|
|
|
|
alt op {
|
|
|
|
ast::eq | ast::ne { C_u8(abi::cmp_glue_op_eq) }
|
|
|
|
ast::lt | ast::ge { C_u8(abi::cmp_glue_op_lt) }
|
|
|
|
ast::le | ast::gt { C_u8(abi::cmp_glue_op_le) }
|
|
|
|
_ { cx.tcx().sess.bug("trans_compare got non-comparison-op"); }
|
|
|
|
}
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
let cmpval = call_cmp_glue(cx, lhs, rhs, rhs_t, llop);
|
2011-02-28 16:36:08 -08:00
|
|
|
|
2011-08-02 18:04:24 -07:00
|
|
|
// Invert the result if necessary.
|
|
|
|
alt op {
|
2012-03-23 14:45:47 +01:00
|
|
|
ast::eq | ast::lt | ast::le { rslt(cx, cmpval) }
|
|
|
|
ast::ne | ast::ge | ast::gt { rslt(cx, Not(cx, cmpval)) }
|
|
|
|
_ { cx.tcx().sess.bug("trans_compare got non-comparison-op"); }
|
2011-02-10 19:40:02 -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,
|
|
|
|
bind Trunc(cx, _, _), bind ZExt(cx, _, _))
|
|
|
|
}
|
|
|
|
|
|
|
|
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 {
|
|
|
|
// FIXME: If shifting by negative values becomes not undefined
|
2012-06-07 14:37:36 -07:00
|
|
|
// then this is wrong. (See discussion at #1570)
|
2012-02-21 21:01:33 -08:00
|
|
|
zext(rhs, lhs_llty)
|
|
|
|
} else {
|
|
|
|
rhs
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
rhs
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-08-02 17:21:28 -07:00
|
|
|
// Important to get types for both lhs and rhs, because one might be _|_
|
|
|
|
// and the other not.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_eager_binop(cx: block, op: ast::binop, lhs: ValueRef,
|
2011-09-27 10:50:18 +02:00
|
|
|
lhs_t: ty::t, rhs: ValueRef, rhs_t: ty::t, dest: dest)
|
2012-02-17 13:17:40 +01:00
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_eager_binop");
|
2011-09-27 10:50:18 +02:00
|
|
|
if dest == ignore { ret cx; }
|
2012-03-15 09:47:03 -04:00
|
|
|
let intype = {
|
|
|
|
if ty::type_is_bot(lhs_t) { rhs_t }
|
|
|
|
else { lhs_t }
|
|
|
|
};
|
2012-02-03 15:15:28 +01:00
|
|
|
let is_float = ty::type_is_fp(intype);
|
2011-08-02 17:21:28 -07:00
|
|
|
|
2012-02-21 21:01:33 -08:00
|
|
|
let rhs = cast_shift_expr_rhs(cx, op, lhs, rhs);
|
|
|
|
|
2012-02-03 15:15:28 +01:00
|
|
|
if op == ast::add && ty::type_is_sequence(intype) {
|
2011-09-27 10:50:18 +02:00
|
|
|
ret tvec::trans_add(cx, intype, lhs, rhs, dest);
|
|
|
|
}
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut cx = cx;
|
|
|
|
let val = alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FAdd(cx, lhs, rhs) }
|
|
|
|
else { Add(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::subtract {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FSub(cx, lhs, rhs) }
|
|
|
|
else { Sub(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::mul {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FMul(cx, lhs, rhs) }
|
|
|
|
else { Mul(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::div {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FDiv(cx, lhs, rhs) }
|
2012-02-03 15:15:28 +01:00
|
|
|
else if ty::type_is_signed(intype) {
|
2011-09-27 10:50:18 +02:00
|
|
|
SDiv(cx, lhs, rhs)
|
|
|
|
} else { UDiv(cx, lhs, rhs) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::rem {
|
2011-09-27 10:50:18 +02:00
|
|
|
if is_float { FRem(cx, lhs, rhs) }
|
2012-02-03 15:15:28 +01:00
|
|
|
else if ty::type_is_signed(intype) {
|
2011-09-27 10:50:18 +02:00
|
|
|
SRem(cx, lhs, rhs)
|
|
|
|
} else { URem(cx, lhs, rhs) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::bitor { Or(cx, lhs, rhs) }
|
|
|
|
ast::bitand { And(cx, lhs, rhs) }
|
|
|
|
ast::bitxor { Xor(cx, lhs, rhs) }
|
2012-05-22 14:59:15 -07:00
|
|
|
ast::shl { Shl(cx, lhs, rhs) }
|
|
|
|
ast::shr {
|
|
|
|
if ty::type_is_signed(intype) {
|
|
|
|
AShr(cx, lhs, rhs)
|
|
|
|
} else { LShr(cx, lhs, rhs) }
|
|
|
|
}
|
2011-09-27 10:50:18 +02:00
|
|
|
_ {
|
|
|
|
let cmpr = trans_compare(cx, op, lhs, lhs_t, rhs, rhs_t);
|
|
|
|
cx = cmpr.bcx;
|
|
|
|
cmpr.val
|
|
|
|
}
|
|
|
|
};
|
|
|
|
ret store_in_dest(cx, val, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_assign_op(bcx: block, ex: @ast::expr, op: ast::binop,
|
|
|
|
dst: @ast::expr, src: @ast::expr) -> block {
|
2012-06-08 16:53:01 -07:00
|
|
|
#debug["%s", expr_to_str(ex)];
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_assign_op");
|
2012-02-02 12:37:17 +01:00
|
|
|
let t = expr_ty(bcx, src);
|
2011-09-27 08:03:06 +02:00
|
|
|
let lhs_res = trans_lval(bcx, dst);
|
2011-10-07 11:20:51 +02:00
|
|
|
assert (lhs_res.kind == owned);
|
2012-01-26 12:26:14 +01:00
|
|
|
|
|
|
|
// A user-defined operator method
|
2012-02-14 15:21:53 -08:00
|
|
|
alt bcx.ccx().maps.method_map.find(ex.id) {
|
2012-01-26 12:26:14 +01:00
|
|
|
some(origin) {
|
|
|
|
let callee_id = ast_util::op_expr_callee_id(ex);
|
2012-02-09 14:33:00 +01:00
|
|
|
let fty = node_id_type(bcx, callee_id);
|
2012-05-14 14:24:16 -07:00
|
|
|
ret trans_call_inner(
|
|
|
|
bcx, ex.info(), fty,
|
|
|
|
expr_ty(bcx, ex),
|
|
|
|
{|bcx|
|
|
|
|
// FIXME provide the already-computed address, not the expr
|
2012-06-07 14:37:36 -07:00
|
|
|
// #2528
|
2012-05-14 14:24:16 -07:00
|
|
|
impl::trans_method_callee(bcx, callee_id, dst, origin)
|
|
|
|
},
|
|
|
|
arg_exprs([src]), save_in(lhs_res.val));
|
2012-01-26 12:26:14 +01:00
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
|
2011-09-27 08:03:06 +02:00
|
|
|
// Special case for `+= [x]`
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t).struct {
|
2011-09-27 08:03:06 +02:00
|
|
|
ty::ty_vec(_) {
|
|
|
|
alt src.node {
|
|
|
|
ast::expr_vec(args, _) {
|
|
|
|
ret tvec::trans_append_literal(lhs_res.bcx,
|
|
|
|
lhs_res.val, t, args);
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val: rhs_val} = trans_temp_expr(lhs_res.bcx, src);
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_sequence(t) {
|
2011-09-27 08:03:06 +02:00
|
|
|
alt op {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-10-05 10:21:48 +02:00
|
|
|
ret tvec::trans_append(bcx, t, lhs_res.val, rhs_val);
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
ret trans_eager_binop(bcx, op, Load(bcx, lhs_res.val), t, rhs_val, t,
|
|
|
|
save_in(lhs_res.val));
|
2011-09-27 08:03:06 +02:00
|
|
|
}
|
|
|
|
|
2012-05-17 20:18:20 -07:00
|
|
|
fn root_value(bcx: block, val: ValueRef, ty: ty::t,
|
|
|
|
scope_id: ast::node_id) {
|
2012-06-08 05:46:29 -07:00
|
|
|
let _icx = bcx.insn_ctxt("root_value");
|
|
|
|
|
2012-05-18 19:02:39 -07:00
|
|
|
if bcx.sess().trace() {
|
|
|
|
trans_trace(
|
|
|
|
bcx, none,
|
|
|
|
#fmt["preserving until end of scope %d", scope_id]);
|
2012-05-17 20:18:20 -07:00
|
|
|
}
|
2012-05-18 19:02:39 -07:00
|
|
|
|
2012-05-28 20:52:11 -07:00
|
|
|
let root_loc = alloca_zeroed(bcx, type_of(bcx.ccx(), ty));
|
2012-05-17 20:18:20 -07:00
|
|
|
copy_val(bcx, INIT, root_loc, val, ty);
|
|
|
|
add_root_cleanup(bcx, scope_id, root_loc, ty);
|
|
|
|
}
|
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
fn autoderef(cx: block, e_id: ast::node_id,
|
|
|
|
v: ValueRef, t: ty::t) -> result_t {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("autoderef");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut v1: ValueRef = v;
|
|
|
|
let mut t1: ty::t = t;
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-05-14 20:32:29 -07:00
|
|
|
let mut derefs = 0u;
|
2012-03-10 20:34:17 -08:00
|
|
|
loop {
|
2012-05-14 20:32:29 -07:00
|
|
|
#debug["autoderef(e_id=%d, v1=%s, t1=%s, derefs=%u)",
|
|
|
|
e_id, val_str(ccx.tn, v1), ty_to_str(ccx.tcx, t1),
|
|
|
|
derefs];
|
|
|
|
|
2012-05-17 20:18:20 -07:00
|
|
|
// root the autoderef'd value, if necessary:
|
2012-05-14 20:32:29 -07:00
|
|
|
derefs += 1u;
|
2012-05-17 20:18:20 -07:00
|
|
|
alt ccx.maps.root_map.find({id:e_id, derefs:derefs}) {
|
|
|
|
none { }
|
2012-05-14 20:32:29 -07:00
|
|
|
some(scope_id) {
|
2012-05-17 20:18:20 -07:00
|
|
|
root_value(cx, v1, t1, scope_id);
|
2012-05-14 20:32:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t1).struct {
|
2011-07-27 14:19:39 +02:00
|
|
|
ty::ty_box(mt) {
|
2012-05-03 22:31:38 -07:00
|
|
|
let body = GEPi(cx, v1, [0u, abi::box_field_body]);
|
2011-07-27 14:19:39 +02:00
|
|
|
t1 = mt.ty;
|
|
|
|
|
|
|
|
// Since we're changing levels of box indirection, we may have
|
2012-01-19 14:24:03 -08:00
|
|
|
// to cast this pointer, since statically-sized enum types have
|
2011-07-27 14:19:39 +02:00
|
|
|
// different types depending on whether they're behind a box
|
|
|
|
// or not.
|
2012-03-12 10:05:15 +01:00
|
|
|
let llty = type_of(ccx, t1);
|
|
|
|
v1 = PointerCast(cx, body, T_ptr(llty));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-22 16:04:27 -07:00
|
|
|
ty::ty_uniq(_) {
|
2012-05-09 14:11:46 -07:00
|
|
|
let derefed = uniq::autoderef(cx, v1, t1);
|
2011-09-22 16:04:27 -07:00
|
|
|
t1 = derefed.t;
|
|
|
|
v1 = derefed.v;
|
|
|
|
}
|
2012-03-14 16:13:05 -07:00
|
|
|
ty::ty_rptr(_, mt) {
|
|
|
|
t1 = mt.ty;
|
|
|
|
v1 = v;
|
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ty::ty_res(did, inner, substs) {
|
|
|
|
t1 = ty::subst(ccx.tcx, substs, inner);
|
2012-05-03 22:31:38 -07:00
|
|
|
v1 = GEPi(cx, v1, [0u, 1u]);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ty::ty_enum(did, substs) {
|
2012-01-25 14:34:31 +01:00
|
|
|
let variants = ty::enum_variants(ccx.tcx, did);
|
2012-02-14 09:10:47 +01:00
|
|
|
if (*variants).len() != 1u || variants[0].args.len() != 1u {
|
2011-07-27 14:19:39 +02:00
|
|
|
break;
|
2011-07-01 13:57:03 +02:00
|
|
|
}
|
2012-05-14 20:32:29 -07:00
|
|
|
t1 = ty::subst(ccx.tcx, substs, variants[0].args[0]);
|
2012-03-12 10:05:15 +01:00
|
|
|
v1 = PointerCast(cx, v1, T_ptr(type_of(ccx, t1)));
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ { break; }
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
2011-07-11 13:12:44 -05:00
|
|
|
v1 = load_if_immediate(cx, v1, t1);
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ret {bcx: cx, val: v1, ty: t1};
|
2011-01-24 18:03:31 -08:00
|
|
|
}
|
|
|
|
|
2012-01-30 21:00:57 -08:00
|
|
|
// refinement types would obviate the need for this
|
|
|
|
enum lazy_binop_ty { lazy_and, lazy_or }
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_lazy_binop(bcx: block, op: lazy_binop_ty, a: @ast::expr,
|
|
|
|
b: @ast::expr, dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_lazy_binop");
|
2012-05-14 14:24:16 -07:00
|
|
|
let {bcx: past_lhs, val: lhs} = {
|
|
|
|
with_scope_result(bcx, a.info(), "lhs") { |bcx|
|
|
|
|
trans_temp_expr(bcx, a)
|
|
|
|
}
|
|
|
|
};
|
2012-02-17 13:17:40 +01:00
|
|
|
if past_lhs.unreachable { ret past_lhs; }
|
|
|
|
let join = sub_block(bcx, "join"), before_rhs = sub_block(bcx, "rhs");
|
2011-09-27 10:50:18 +02:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
alt op {
|
|
|
|
lazy_and { CondBr(past_lhs, lhs, before_rhs.llbb, join.llbb); }
|
|
|
|
lazy_or { CondBr(past_lhs, lhs, join.llbb, before_rhs.llbb); }
|
2011-09-27 10:50:18 +02:00
|
|
|
}
|
2012-05-14 14:24:16 -07:00
|
|
|
let {bcx: past_rhs, val: rhs} = {
|
|
|
|
with_scope_result(before_rhs, b.info(), "rhs") { |bcx|
|
|
|
|
trans_temp_expr(bcx, b)
|
|
|
|
}
|
|
|
|
};
|
2012-02-17 13:17:40 +01:00
|
|
|
|
|
|
|
if past_rhs.unreachable { ret store_in_dest(join, lhs, dest); }
|
|
|
|
Br(past_rhs, join.llbb);
|
|
|
|
let phi = Phi(join, T_bool(), [lhs, rhs], [past_lhs.llbb, past_rhs.llbb]);
|
|
|
|
ret store_in_dest(join, phi, dest);
|
2011-09-27 10:50:18 +02:00
|
|
|
}
|
2011-08-19 15:16:48 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_binary(bcx: block, op: ast::binop, lhs: @ast::expr,
|
|
|
|
rhs: @ast::expr, dest: dest, ex: @ast::expr) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_binary");
|
2012-01-26 12:26:14 +01:00
|
|
|
// User-defined operators
|
2012-02-14 15:21:53 -08:00
|
|
|
alt bcx.ccx().maps.method_map.find(ex.id) {
|
2012-01-26 12:26:14 +01:00
|
|
|
some(origin) {
|
|
|
|
let callee_id = ast_util::op_expr_callee_id(ex);
|
2012-02-09 14:33:00 +01:00
|
|
|
let fty = node_id_type(bcx, callee_id);
|
2012-05-14 14:24:16 -07:00
|
|
|
ret trans_call_inner(
|
|
|
|
bcx, ex.info(), fty,
|
|
|
|
expr_ty(bcx, ex),
|
|
|
|
{|bcx|
|
|
|
|
impl::trans_method_callee(bcx, callee_id, lhs, origin)
|
|
|
|
},
|
|
|
|
arg_exprs([rhs]), dest);
|
2012-01-26 12:26:14 +01:00
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
|
2010-10-19 17:24:15 -07:00
|
|
|
// First couple cases are lazy:
|
2011-07-27 14:19:39 +02:00
|
|
|
alt op {
|
2012-01-30 21:00:57 -08:00
|
|
|
ast::and {
|
|
|
|
ret trans_lazy_binop(bcx, lazy_and, lhs, rhs, dest);
|
|
|
|
}
|
|
|
|
ast::or {
|
|
|
|
ret trans_lazy_binop(bcx, lazy_or, lhs, rhs, dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {
|
|
|
|
// Remaining cases are eager:
|
2012-01-26 15:52:28 +01:00
|
|
|
let lhs_res = trans_temp_expr(bcx, lhs);
|
|
|
|
let rhs_res = trans_temp_expr(lhs_res.bcx, rhs);
|
|
|
|
ret trans_eager_binop(rhs_res.bcx, op, lhs_res.val,
|
2012-02-02 12:37:17 +01:00
|
|
|
expr_ty(bcx, lhs), rhs_res.val,
|
|
|
|
expr_ty(bcx, rhs), dest);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-28 14:01:21 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_if(cx: block, cond: @ast::expr, thn: ast::blk,
|
2012-01-31 17:05:20 -08:00
|
|
|
els: option<@ast::expr>, dest: dest)
|
2012-02-17 13:17:40 +01:00
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_if");
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val: cond_val} = trans_temp_expr(cx, cond);
|
2011-08-03 13:05:46 -07:00
|
|
|
|
2011-09-23 21:13:50 +02:00
|
|
|
let then_dest = dup_for_join(dest);
|
|
|
|
let else_dest = dup_for_join(dest);
|
2012-05-14 14:24:16 -07:00
|
|
|
let then_cx = scope_block(bcx, thn.info(), "then");
|
|
|
|
let else_cx = scope_block(bcx, els.info(), "else");
|
2011-09-23 21:13:50 +02:00
|
|
|
CondBr(bcx, cond_val, then_cx.llbb, else_cx.llbb);
|
2012-02-15 13:57:29 +01:00
|
|
|
let then_bcx = trans_block(then_cx, thn, then_dest);
|
2012-03-15 09:47:03 -04:00
|
|
|
let then_bcx = trans_block_cleanups(then_bcx, then_cx);
|
2011-07-27 14:48:34 +02:00
|
|
|
// Calling trans_block directly instead of trans_expr
|
|
|
|
// because trans_expr will create another scope block
|
|
|
|
// context for the block, but we've already got the
|
|
|
|
// 'else' context
|
2012-02-15 13:57:29 +01:00
|
|
|
let else_bcx = alt els {
|
2011-09-23 21:13:50 +02:00
|
|
|
some(elexpr) {
|
|
|
|
alt elexpr.node {
|
|
|
|
ast::expr_if(_, _, _) {
|
|
|
|
let elseif_blk = ast_util::block_from_expr(elexpr);
|
2012-02-15 13:57:29 +01:00
|
|
|
trans_block(else_cx, elseif_blk, else_dest)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-23 21:13:50 +02:00
|
|
|
ast::expr_block(blk) {
|
2012-02-15 13:57:29 +01:00
|
|
|
trans_block(else_cx, blk, else_dest)
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
2012-01-30 21:00:57 -08:00
|
|
|
// would be nice to have a constraint on ifs
|
2012-03-05 16:27:27 -08:00
|
|
|
_ { cx.tcx().sess.bug("strange alternative in if"); }
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
_ { else_cx }
|
|
|
|
};
|
2012-03-15 09:47:03 -04:00
|
|
|
let else_bcx = trans_block_cleanups(else_bcx, else_cx);
|
2012-02-15 13:57:29 +01:00
|
|
|
ret join_returns(cx, [then_bcx, else_bcx], [then_dest, else_dest], dest);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_while(cx: block, cond: @ast::expr, body: ast::blk)
|
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_while");
|
2012-02-17 13:17:40 +01:00
|
|
|
let next_cx = sub_block(cx, "while next");
|
2012-05-14 14:24:16 -07:00
|
|
|
let loop_cx = loop_scope_block(cx, next_cx, "`while`", body.info());
|
|
|
|
let cond_cx = scope_block(loop_cx, cond.info(), "while loop cond");
|
|
|
|
let body_cx = scope_block(loop_cx, body.info(), "while loop body");
|
2012-03-13 17:24:39 -07:00
|
|
|
Br(cx, loop_cx.llbb);
|
|
|
|
Br(loop_cx, cond_cx.llbb);
|
2011-10-05 11:26:27 +02:00
|
|
|
let cond_res = trans_temp_expr(cond_cx, cond);
|
2011-07-27 14:19:39 +02:00
|
|
|
let cond_bcx = trans_block_cleanups(cond_res.bcx, cond_cx);
|
2011-08-30 09:59:30 +02:00
|
|
|
CondBr(cond_bcx, cond_res.val, body_cx.llbb, next_cx.llbb);
|
2012-02-15 13:57:29 +01:00
|
|
|
let body_end = trans_block(body_cx, body, ignore);
|
|
|
|
cleanup_and_Br(body_end, body_cx, cond_cx.llbb);
|
2011-09-27 08:03:06 +02:00
|
|
|
ret next_cx;
|
2010-11-03 11:05:15 -07:00
|
|
|
}
|
|
|
|
|
2012-03-09 16:11:56 -08:00
|
|
|
fn trans_loop(cx:block, body: ast::blk) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_loop");
|
2012-03-09 16:11:56 -08:00
|
|
|
let next_cx = sub_block(cx, "next");
|
2012-05-14 14:24:16 -07:00
|
|
|
let body_cx = loop_scope_block(cx, next_cx, "`loop`", body.info());
|
2012-03-09 16:11:56 -08:00
|
|
|
let body_end = trans_block(body_cx, body, ignore);
|
|
|
|
cleanup_and_Br(body_end, body_cx, body_cx.llbb);
|
|
|
|
Br(cx, body_cx.llbb);
|
|
|
|
ret next_cx;
|
|
|
|
}
|
|
|
|
|
2012-01-19 14:24:03 -08:00
|
|
|
enum lval_kind {
|
2012-01-19 17:56:05 -08:00
|
|
|
temporary, //< Temporary value passed by value if of immediate type
|
|
|
|
owned, //< Non-temporary value passed by pointer
|
|
|
|
owned_imm, //< Non-temporary value passed by value
|
2011-12-19 12:50:31 -08:00
|
|
|
}
|
2011-12-10 08:38:40 -08:00
|
|
|
type local_var_result = {val: ValueRef, kind: lval_kind};
|
2012-02-17 13:17:40 +01:00
|
|
|
type lval_result = {bcx: block, val: ValueRef, kind: lval_kind};
|
2012-01-19 14:24:03 -08:00
|
|
|
enum callee_env {
|
2012-01-19 17:56:05 -08:00
|
|
|
null_env,
|
|
|
|
is_closure,
|
2012-03-16 12:57:07 +01:00
|
|
|
self_env(ValueRef, ty::t, option<ValueRef>),
|
2012-01-02 16:50:51 +01:00
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
type lval_maybe_callee = {bcx: block,
|
2011-09-16 16:27:34 +02:00
|
|
|
val: ValueRef,
|
2011-10-07 11:20:51 +02:00
|
|
|
kind: lval_kind,
|
2012-03-23 15:05:16 +01:00
|
|
|
env: callee_env};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn null_env_ptr(bcx: block) -> ValueRef {
|
2012-02-21 14:20:18 +01:00
|
|
|
C_null(T_opaque_box_ptr(bcx.ccx()))
|
2011-09-18 22:05:58 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn lval_from_local_var(bcx: block, r: local_var_result) -> lval_result {
|
2011-12-10 08:38:40 -08:00
|
|
|
ret { bcx: bcx, val: r.val, kind: r.kind };
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn lval_owned(bcx: block, val: ValueRef) -> lval_result {
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: owned};
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
fn lval_temp(bcx: block, val: ValueRef) -> lval_result {
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: temporary};
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn lval_no_env(bcx: block, val: ValueRef, kind: lval_kind)
|
2011-09-16 16:27:34 +02:00
|
|
|
-> lval_maybe_callee {
|
2012-03-23 15:05:16 +01:00
|
|
|
ret {bcx: bcx, val: val, kind: kind, env: is_closure};
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-03-09 10:47:40 +01:00
|
|
|
fn trans_external_path(ccx: @crate_ctxt, did: ast::def_id, t: ty::t)
|
|
|
|
-> ValueRef {
|
2012-02-03 09:53:37 +01:00
|
|
|
let name = csearch::get_symbol(ccx.sess.cstore, did);
|
2012-04-09 14:38:53 +08:00
|
|
|
alt ty::get(t).struct {
|
|
|
|
ty::ty_fn(_) {
|
|
|
|
let llty = type_of_fn_from_ty(ccx, t);
|
|
|
|
ret get_extern_fn(ccx.externs, ccx.llmod, name,
|
|
|
|
lib::llvm::CCallConv, llty);
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
let llty = type_of(ccx, t);
|
|
|
|
ret get_extern_const(ccx.externs, ccx.llmod, name, llty);
|
|
|
|
}
|
2012-03-09 10:47:40 +01:00
|
|
|
};
|
2011-03-30 18:15:29 -07:00
|
|
|
}
|
|
|
|
|
2012-03-12 16:31:22 +01:00
|
|
|
fn normalize_for_monomorphization(tcx: ty::ctxt, ty: ty::t) -> option<ty::t> {
|
2012-06-07 14:37:36 -07:00
|
|
|
// FIXME[mono] could do this recursively. is that worthwhile? (#2529)
|
2012-03-12 16:31:22 +01:00
|
|
|
alt ty::get(ty).struct {
|
|
|
|
ty::ty_box(mt) { some(ty::mk_opaque_box(tcx)) }
|
2012-05-24 23:44:58 -07:00
|
|
|
ty::ty_fn(fty) { some(ty::mk_fn(tcx, {purity: ast::impure_fn,
|
|
|
|
proto: fty.proto,
|
2012-03-12 16:31:22 +01:00
|
|
|
inputs: [],
|
|
|
|
output: ty::mk_nil(tcx),
|
|
|
|
ret_style: ast::return_val,
|
|
|
|
constraints: []})) }
|
2012-05-24 23:44:58 -07:00
|
|
|
ty::ty_iface(_, _) { some(ty::mk_fn(tcx, {purity: ast::impure_fn,
|
|
|
|
proto: ast::proto_box,
|
2012-03-12 16:31:22 +01:00
|
|
|
inputs: [],
|
|
|
|
output: ty::mk_nil(tcx),
|
|
|
|
ret_style: ast::return_val,
|
|
|
|
constraints: []})) }
|
|
|
|
ty::ty_ptr(_) { some(ty::mk_uint(tcx)) }
|
|
|
|
_ { none }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn make_mono_id(ccx: @crate_ctxt, item: ast::def_id, substs: [ty::t],
|
|
|
|
vtables: option<typeck::vtable_res>,
|
|
|
|
param_uses: option<[type_use::type_uses]>) -> mono_id {
|
|
|
|
let precise_param_ids = alt vtables {
|
|
|
|
some(vts) {
|
|
|
|
let bounds = ty::lookup_item_type(ccx.tcx, item).bounds;
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 0u;
|
2012-03-12 16:31:22 +01:00
|
|
|
vec::map2(*bounds, substs, {|bounds, subst|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut v = [];
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(*bounds) {|bound|
|
2012-03-12 16:31:22 +01:00
|
|
|
alt bound {
|
|
|
|
ty::bound_iface(_) {
|
|
|
|
v += [impl::vtable_id(ccx, vts[i])];
|
|
|
|
i += 1u;
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
mono_precise(subst, if v.len() > 0u { some(v) } else { none })
|
|
|
|
})
|
|
|
|
}
|
|
|
|
none {
|
|
|
|
vec::map(substs, {|subst| mono_precise(subst, none)})
|
|
|
|
}
|
|
|
|
};
|
|
|
|
let param_ids = alt param_uses {
|
|
|
|
some(uses) {
|
|
|
|
vec::map2(precise_param_ids, uses, {|id, uses|
|
|
|
|
alt check id {
|
|
|
|
mono_precise(_, some(_)) { id }
|
|
|
|
mono_precise(subst, none) {
|
|
|
|
if uses == 0u { mono_any }
|
|
|
|
else if uses == type_use::use_repr &&
|
|
|
|
!ty::type_needs_drop(ccx.tcx, subst) {
|
|
|
|
let llty = type_of(ccx, subst);
|
|
|
|
let size = shape::llsize_of_real(ccx, llty);
|
2012-04-26 21:44:27 -07:00
|
|
|
let align = shape::llalign_of_pref(ccx, llty);
|
2012-03-12 16:31:22 +01:00
|
|
|
// Special value for nil to prevent problems with undef
|
|
|
|
// return pointers.
|
|
|
|
if size == 1u && ty::type_is_nil(subst) {
|
|
|
|
mono_repr(0u, 0u)
|
|
|
|
} else { mono_repr(size, align) }
|
|
|
|
} else { id }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
})
|
|
|
|
}
|
|
|
|
none { precise_param_ids }
|
|
|
|
};
|
|
|
|
@{def: item, params: param_ids}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn monomorphic_fn(ccx: @crate_ctxt, fn_id: ast::def_id, real_substs: [ty::t],
|
2012-03-21 15:42:20 +01:00
|
|
|
vtables: option<typeck::vtable_res>,
|
|
|
|
ref_id: option<ast::node_id>)
|
2012-03-23 15:05:16 +01:00
|
|
|
-> {val: ValueRef, must_cast: bool} {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("monomorphic_fn");
|
2012-03-09 11:43:46 +01:00
|
|
|
let mut must_cast = false;
|
2012-03-12 16:31:22 +01:00
|
|
|
let substs = vec::map(real_substs, {|t|
|
|
|
|
alt normalize_for_monomorphization(ccx.tcx, t) {
|
|
|
|
some(t) { must_cast = true; t }
|
|
|
|
none { t }
|
2012-02-07 11:25:04 +01:00
|
|
|
}
|
|
|
|
});
|
2012-03-12 16:31:22 +01:00
|
|
|
|
2012-05-25 15:29:27 -07:00
|
|
|
#debug["monomorphic_fn(fn_id=%? (%s), real_substs=%?, substs=%?",
|
|
|
|
fn_id, ty::item_path_str(ccx.tcx, fn_id),
|
|
|
|
real_substs.map({|s| ty_to_str(ccx.tcx, s)}),
|
|
|
|
substs.map({|s| ty_to_str(ccx.tcx, s)})];
|
|
|
|
|
|
|
|
for real_substs.each() {|s| assert !ty::type_has_params(s); };
|
|
|
|
for substs.each() {|s| assert !ty::type_has_params(s); };
|
|
|
|
|
2012-03-12 16:31:22 +01:00
|
|
|
let param_uses = type_use::type_uses_for(ccx, fn_id, substs.len());
|
|
|
|
let hash_id = make_mono_id(ccx, fn_id, substs, vtables, some(param_uses));
|
|
|
|
if vec::any(hash_id.params,
|
|
|
|
{|p| alt p { mono_precise(_, _) { false } _ { true } } }) {
|
|
|
|
must_cast = true;
|
|
|
|
}
|
2012-02-02 12:37:17 +01:00
|
|
|
alt ccx.monomorphized.find(hash_id) {
|
2012-03-12 16:31:22 +01:00
|
|
|
some(val) {
|
2012-03-23 15:05:16 +01:00
|
|
|
ret {val: val, must_cast: must_cast};
|
2012-03-12 16:31:22 +01:00
|
|
|
}
|
2012-02-02 12:37:17 +01:00
|
|
|
none {}
|
|
|
|
}
|
2012-02-09 11:17:11 +01:00
|
|
|
|
2012-02-02 12:37:17 +01:00
|
|
|
let tpt = ty::lookup_item_type(ccx.tcx, fn_id);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut item_ty = tpt.ty;
|
2012-02-09 14:33:00 +01:00
|
|
|
|
2012-05-29 14:39:22 -07:00
|
|
|
let map_node = session::expect(ccx.sess, ccx.tcx.items.find(fn_id.node),
|
|
|
|
{|| #fmt("While monomorphizing %?, couldn't find it in the item map \
|
|
|
|
(may have attempted to monomorphize an item defined in a different \
|
|
|
|
crate?)", fn_id)});
|
2012-02-09 14:33:00 +01:00
|
|
|
// Get the path so that we can create a symbol
|
2012-04-23 16:44:52 +02:00
|
|
|
let (pt, name, span) = alt map_node {
|
2012-03-08 21:16:04 +01:00
|
|
|
ast_map::node_item(i, pt) {
|
|
|
|
alt i.node {
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_res(_, _, _, dtor_id, _, _) {
|
2012-03-08 21:16:04 +01:00
|
|
|
item_ty = ty::node_id_to_type(ccx.tcx, dtor_id);
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
2012-04-23 16:44:52 +02:00
|
|
|
(pt, i.ident, i.span)
|
2012-03-08 21:16:04 +01:00
|
|
|
}
|
2012-04-23 16:44:52 +02:00
|
|
|
ast_map::node_variant(v, enm, pt) { (pt, v.node.name, enm.span) }
|
|
|
|
ast_map::node_method(m, _, pt) { (pt, m.ident, m.span) }
|
2012-03-23 15:05:16 +01:00
|
|
|
ast_map::node_native_item(i, ast::native_abi_rust_intrinsic, pt)
|
2012-04-23 16:44:52 +02:00
|
|
|
{ (pt, i.ident, i.span) }
|
2012-03-09 11:43:46 +01:00
|
|
|
ast_map::node_native_item(_, abi, _) {
|
2012-03-09 10:47:40 +01:00
|
|
|
// Natives don't have to be monomorphized.
|
2012-03-09 11:43:46 +01:00
|
|
|
ret {val: get_item_val(ccx, fn_id.node),
|
2012-03-23 15:05:16 +01:00
|
|
|
must_cast: true};
|
2012-03-09 10:47:40 +01:00
|
|
|
}
|
2012-05-22 21:44:28 -04:00
|
|
|
ast_map::node_ctor(nm, _, ct, pt) { (pt, nm, alt ct {
|
|
|
|
ast_map::res_ctor(_, _, sp) { sp }
|
|
|
|
ast_map::class_ctor(ct_, _) { ct_.span }}) }
|
2012-06-10 00:49:59 -07:00
|
|
|
ast_map::node_dtor(_, dtor, _, pt) {(pt, @"drop", dtor.span)}
|
2012-05-22 21:44:28 -04:00
|
|
|
ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
|
|
|
|
ast_map::node_export(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize an export")
|
|
|
|
}
|
|
|
|
ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") }
|
|
|
|
ast_map::node_block(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize a block")
|
|
|
|
}
|
|
|
|
ast_map::node_local(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize a local")
|
|
|
|
}
|
2012-02-09 14:33:00 +01:00
|
|
|
};
|
2012-04-18 21:26:25 -07:00
|
|
|
let mono_ty = ty::subst_tps(ccx.tcx, substs, item_ty);
|
2012-03-09 10:47:40 +01:00
|
|
|
let llfty = type_of_fn_from_ty(ccx, mono_ty);
|
2012-03-08 21:16:04 +01:00
|
|
|
|
2012-04-13 12:22:35 -07:00
|
|
|
let depth = option::get_default(ccx.monomorphizing.find(fn_id), 0u);
|
2012-04-23 16:44:52 +02:00
|
|
|
// Random cut-off -- code that needs to instantiate the same function
|
|
|
|
// recursively more than ten times can probably safely be assumed to be
|
|
|
|
// causing an infinite expansion.
|
|
|
|
if depth > 10u {
|
|
|
|
ccx.sess.span_fatal(
|
|
|
|
span, "overly deep expansion of inlined function");
|
|
|
|
}
|
|
|
|
ccx.monomorphizing.insert(fn_id, depth + 1u);
|
|
|
|
|
2012-06-10 00:49:59 -07:00
|
|
|
let pt = *pt + [path_name(@ccx.names(*name))];
|
2012-04-07 17:00:11 -07:00
|
|
|
let s = mangle_exported_name(ccx, pt, mono_ty);
|
2012-05-22 21:44:28 -04:00
|
|
|
|
|
|
|
let mk_lldecl = {||
|
|
|
|
let lldecl = decl_internal_cdecl_fn(ccx.llmod, s, llfty);
|
|
|
|
ccx.monomorphized.insert(hash_id, lldecl);
|
|
|
|
lldecl
|
|
|
|
};
|
2012-02-09 14:33:00 +01:00
|
|
|
|
2012-03-08 16:17:59 +01:00
|
|
|
let psubsts = some({tys: substs, vtables: vtables, bounds: tpt.bounds});
|
2012-05-22 21:44:28 -04:00
|
|
|
let lldecl = alt map_node {
|
2012-03-08 11:31:12 +01:00
|
|
|
ast_map::node_item(i@@{node: ast::item_fn(decl, _, body), _}, _) {
|
2012-05-22 21:44:28 -04:00
|
|
|
let d = mk_lldecl();
|
|
|
|
set_inline_hint_if_appr(i.attrs, d);
|
|
|
|
trans_fn(ccx, pt, decl, body, d, no_self, psubsts, fn_id.node);
|
|
|
|
d
|
2012-02-09 14:33:00 +01:00
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ast_map::node_item(
|
2012-05-22 21:44:28 -04:00
|
|
|
@{node: ast::item_res(dt, _, body, d_id, _, _), _}, _) {
|
|
|
|
let d = mk_lldecl();
|
|
|
|
trans_fn(ccx, pt, dt, body, d, no_self, psubsts, d_id);
|
|
|
|
d
|
|
|
|
}
|
|
|
|
ast_map::node_item(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize this kind of item")
|
2012-03-08 21:16:04 +01:00
|
|
|
}
|
2012-03-21 15:42:20 +01:00
|
|
|
ast_map::node_native_item(i, _, _) {
|
2012-05-22 21:44:28 -04:00
|
|
|
let d = mk_lldecl();
|
|
|
|
native::trans_intrinsic(ccx, d, i, pt, option::get(psubsts),
|
2012-03-23 15:05:16 +01:00
|
|
|
ref_id);
|
2012-05-22 21:44:28 -04:00
|
|
|
d
|
2012-03-21 15:42:20 +01:00
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
ast_map::node_variant(v, enum_item, _) {
|
|
|
|
let tvs = ty::enum_variants(ccx.tcx, local_def(enum_item.id));
|
2012-02-08 10:05:44 +01:00
|
|
|
let this_tv = option::get(vec::find(*tvs, {|tv|
|
|
|
|
tv.id.node == fn_id.node}));
|
2012-05-22 21:44:28 -04:00
|
|
|
let d = mk_lldecl();
|
|
|
|
set_inline_hint(d);
|
2012-03-07 12:21:08 +01:00
|
|
|
trans_enum_variant(ccx, enum_item.id, v, this_tv.disr_val,
|
2012-05-22 21:44:28 -04:00
|
|
|
(*tvs).len() == 1u, psubsts, d);
|
|
|
|
d
|
2012-02-09 11:17:11 +01:00
|
|
|
}
|
2012-03-01 19:37:52 -08:00
|
|
|
ast_map::node_method(mth, impl_def_id, _) {
|
2012-05-22 21:44:28 -04:00
|
|
|
let d = mk_lldecl();
|
|
|
|
set_inline_hint_if_appr(mth.attrs, d);
|
2012-03-07 12:54:00 +01:00
|
|
|
let selfty = ty::node_id_to_type(ccx.tcx, mth.self_id);
|
2012-04-18 21:26:25 -07:00
|
|
|
let selfty = ty::subst_tps(ccx.tcx, substs, selfty);
|
2012-05-22 21:44:28 -04:00
|
|
|
trans_fn(ccx, pt, mth.decl, mth.body, d,
|
2012-03-23 19:49:01 -07:00
|
|
|
impl_self(selfty), psubsts, fn_id.node);
|
2012-05-22 21:44:28 -04:00
|
|
|
d
|
2012-02-02 12:37:17 +01:00
|
|
|
}
|
2012-04-10 10:52:06 -07:00
|
|
|
ast_map::node_ctor(nm, tps, ct, _) {
|
2012-05-22 21:44:28 -04:00
|
|
|
let d = mk_lldecl();
|
2012-04-10 10:52:06 -07:00
|
|
|
alt ct {
|
|
|
|
ast_map::res_ctor(decl,_, _) {
|
2012-05-22 21:44:28 -04:00
|
|
|
set_inline_hint(d);
|
|
|
|
trans_res_ctor(ccx, pt, decl, fn_id.node, psubsts, d);
|
|
|
|
d
|
2012-03-08 11:31:12 +01:00
|
|
|
}
|
2012-04-10 10:52:06 -07:00
|
|
|
ast_map::class_ctor(ctor, parent_id) {
|
|
|
|
// ctors don't have attrs, at least not right now
|
2012-04-02 10:48:32 -07:00
|
|
|
let tp_tys: [ty::t] = ty::ty_params_to_tys(ccx.tcx, tps);
|
2012-05-22 21:44:28 -04:00
|
|
|
trans_class_ctor(ccx, pt, ctor.node.dec, ctor.node.body, d,
|
2012-04-11 09:24:46 -07:00
|
|
|
option::get_default(psubsts,
|
2012-04-02 10:48:32 -07:00
|
|
|
{tys:tp_tys, vtables: none, bounds: @[]}),
|
2012-04-10 10:52:06 -07:00
|
|
|
fn_id.node, parent_id, ctor.span);
|
2012-05-22 21:44:28 -04:00
|
|
|
d
|
2012-03-08 11:31:12 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-22 21:44:28 -04:00
|
|
|
ast_map::node_dtor(_, dtor, _, pt) {
|
|
|
|
let parent_id = alt ty::ty_to_def_id(ty::node_id_to_type(ccx.tcx,
|
|
|
|
dtor.node.self_id)) {
|
|
|
|
some(did) { did }
|
|
|
|
none { ccx.sess.span_bug(dtor.span, "Bad self ty in \
|
|
|
|
dtor"); }
|
|
|
|
};
|
|
|
|
trans_class_dtor(ccx, *pt, dtor.node.body,
|
2012-06-04 17:01:53 -07:00
|
|
|
dtor.node.id, psubsts, some(hash_id), parent_id)
|
2012-05-22 21:44:28 -04:00
|
|
|
}
|
|
|
|
// Ugh -- but this ensures any new variants won't be forgotten
|
|
|
|
ast_map::node_expr(*) { ccx.tcx.sess.bug("Can't monomorphize an expr") }
|
|
|
|
ast_map::node_export(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize an export")
|
|
|
|
}
|
|
|
|
ast_map::node_arg(*) { ccx.tcx.sess.bug("Can't monomorphize an arg") }
|
|
|
|
ast_map::node_block(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize a block")
|
|
|
|
}
|
|
|
|
ast_map::node_local(*) {
|
|
|
|
ccx.tcx.sess.bug("Can't monomorphize a local")
|
|
|
|
}
|
|
|
|
};
|
2012-04-23 16:44:52 +02:00
|
|
|
ccx.monomorphizing.insert(fn_id, depth);
|
2012-03-23 15:05:16 +01:00
|
|
|
{val: lldecl, must_cast: must_cast}
|
2012-02-02 12:37:17 +01:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn maybe_instantiate_inline(ccx: @crate_ctxt, fn_id: ast::def_id)
|
2012-03-06 11:33:25 +01:00
|
|
|
-> ast::def_id {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("maybe_instantiate_inline");
|
2012-03-06 11:33:25 +01:00
|
|
|
alt ccx.external.find(fn_id) {
|
2012-03-07 15:13:31 -08:00
|
|
|
some(some(node_id)) {
|
|
|
|
// Already inline
|
|
|
|
#debug["maybe_instantiate_inline(%s): already inline as node id %d",
|
|
|
|
ty::item_path_str(ccx.tcx, fn_id), node_id];
|
|
|
|
local_def(node_id)
|
|
|
|
}
|
2012-03-06 11:33:25 +01:00
|
|
|
some(none) { fn_id } // Not inlinable
|
|
|
|
none { // Not seen yet
|
2012-06-12 16:25:09 -07:00
|
|
|
alt csearch::maybe_get_item_ast(
|
2012-05-14 17:46:45 -07:00
|
|
|
ccx.tcx, fn_id,
|
|
|
|
bind astencode::decode_inlined_item(_, _, ccx.maps, _, _)) {
|
|
|
|
|
2012-03-08 23:13:57 +01:00
|
|
|
csearch::not_found {
|
|
|
|
ccx.external.insert(fn_id, none);
|
|
|
|
fn_id
|
|
|
|
}
|
|
|
|
csearch::found(ast::ii_item(item)) {
|
2012-03-06 11:33:25 +01:00
|
|
|
ccx.external.insert(fn_id, some(item.id));
|
|
|
|
trans_item(ccx, *item);
|
|
|
|
local_def(item.id)
|
|
|
|
}
|
2012-04-10 10:52:06 -07:00
|
|
|
csearch::found(ast::ii_ctor(ctor, nm, tps, parent_id)) {
|
|
|
|
ccx.external.insert(fn_id, some(ctor.node.id));
|
|
|
|
local_def(ctor.node.id)
|
|
|
|
}
|
2012-03-21 15:42:20 +01:00
|
|
|
csearch::found(ast::ii_native(item)) {
|
|
|
|
ccx.external.insert(fn_id, some(item.id));
|
|
|
|
local_def(item.id)
|
|
|
|
}
|
2012-03-08 23:13:57 +01:00
|
|
|
csearch::found_parent(parent_id, ast::ii_item(item)) {
|
|
|
|
ccx.external.insert(parent_id, some(item.id));
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut my_id = 0;
|
2012-03-08 23:13:57 +01:00
|
|
|
alt check item.node {
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_enum(_, _, _) {
|
2012-03-08 23:13:57 +01:00
|
|
|
let vs_here = ty::enum_variants(ccx.tcx, local_def(item.id));
|
|
|
|
let vs_there = ty::enum_variants(ccx.tcx, parent_id);
|
|
|
|
vec::iter2(*vs_here, *vs_there) {|here, there|
|
|
|
|
if there.id == fn_id { my_id = here.id.node; }
|
|
|
|
ccx.external.insert(there.id, some(here.id.node));
|
|
|
|
}
|
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_res(_, _, _, _, ctor_id, _) {
|
|
|
|
my_id = ctor_id;
|
|
|
|
}
|
2012-03-08 23:13:57 +01:00
|
|
|
}
|
|
|
|
trans_item(ccx, *item);
|
|
|
|
local_def(my_id)
|
|
|
|
}
|
2012-06-12 16:25:09 -07:00
|
|
|
csearch::found_parent(_, _) {
|
|
|
|
ccx.sess.bug("maybe_get_item_ast returned a found_parent \
|
|
|
|
with a non-item parent");
|
|
|
|
}
|
2012-03-08 23:13:57 +01:00
|
|
|
csearch::found(ast::ii_method(impl_did, mth)) {
|
2012-03-06 11:33:25 +01:00
|
|
|
ccx.external.insert(fn_id, some(mth.id));
|
2012-04-18 21:26:25 -07:00
|
|
|
let {bounds: impl_bnds, rp: _, ty: impl_ty} =
|
2012-03-20 13:19:33 +01:00
|
|
|
ty::lookup_item_type(ccx.tcx, impl_did);
|
|
|
|
if (*impl_bnds).len() + mth.tps.len() == 0u {
|
|
|
|
let llfn = get_item_val(ccx, mth.id);
|
|
|
|
let path = ty::item_path(ccx.tcx, impl_did) +
|
|
|
|
[path_name(mth.ident)];
|
|
|
|
trans_fn(ccx, path, mth.decl, mth.body,
|
2012-03-23 19:49:01 -07:00
|
|
|
llfn, impl_self(impl_ty), none, mth.id);
|
2012-03-06 11:33:25 +01:00
|
|
|
}
|
|
|
|
local_def(mth.id)
|
|
|
|
}
|
2012-06-12 16:25:09 -07:00
|
|
|
csearch::found(ast::ii_dtor(dtor, nm, tps, parent_id)) {
|
|
|
|
ccx.external.insert(fn_id, some(dtor.node.id));
|
|
|
|
local_def(dtor.node.id)
|
|
|
|
}
|
2012-03-06 11:33:25 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-09 13:35:20 +01:00
|
|
|
fn lval_static_fn(bcx: block, fn_id: ast::def_id, id: ast::node_id)
|
|
|
|
-> lval_maybe_callee {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("lval_static_fn");
|
2012-03-09 13:35:20 +01:00
|
|
|
let vts = option::map(bcx.ccx().maps.vtable_map.find(id), {|vts|
|
|
|
|
impl::resolve_vtables_in_fn_ctxt(bcx.fcx, vts)
|
|
|
|
});
|
|
|
|
lval_static_fn_inner(bcx, fn_id, id, node_id_type_params(bcx, id), vts)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lval_static_fn_inner(bcx: block, fn_id: ast::def_id, id: ast::node_id,
|
|
|
|
tys: [ty::t], vtables: option<typeck::vtable_res>)
|
2011-12-14 14:38:25 +01:00
|
|
|
-> lval_maybe_callee {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("lval_static_fn_inner");
|
2012-03-09 13:35:20 +01:00
|
|
|
let ccx = bcx.ccx(), tcx = ccx.tcx;
|
2012-02-14 15:21:53 -08:00
|
|
|
let tpt = ty::lookup_item_type(tcx, fn_id);
|
|
|
|
|
|
|
|
// Check whether this fn has an inlined copy and, if so, redirect fn_id to
|
|
|
|
// the local id of the inlined copy.
|
2012-03-06 06:58:31 -08:00
|
|
|
let fn_id = if fn_id.crate != ast::local_crate {
|
2012-03-06 11:33:25 +01:00
|
|
|
maybe_instantiate_inline(ccx, fn_id)
|
|
|
|
} else { fn_id };
|
2012-02-14 15:21:53 -08:00
|
|
|
|
2012-03-09 13:35:20 +01:00
|
|
|
if fn_id.crate == ast::local_crate && tys.len() > 0u {
|
2012-03-23 15:05:16 +01:00
|
|
|
let mut {val, must_cast} =
|
2012-03-21 15:42:20 +01:00
|
|
|
monomorphic_fn(ccx, fn_id, tys, vtables, some(id));
|
2012-03-09 13:35:20 +01:00
|
|
|
if must_cast {
|
|
|
|
val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty(
|
|
|
|
ccx, node_id_type(bcx, id))));
|
2012-02-08 10:05:44 +01:00
|
|
|
}
|
2012-03-23 15:05:16 +01:00
|
|
|
ret {bcx: bcx, val: val, kind: owned, env: null_env};
|
2012-02-02 12:37:17 +01:00
|
|
|
}
|
2012-02-14 15:21:53 -08:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut val = if fn_id.crate == ast::local_crate {
|
2011-03-30 18:15:29 -07:00
|
|
|
// Internal reference.
|
2012-03-07 12:21:08 +01:00
|
|
|
get_item_val(ccx, fn_id.node)
|
2011-03-30 18:15:29 -07:00
|
|
|
} else {
|
|
|
|
// External reference.
|
2012-03-09 10:47:40 +01:00
|
|
|
trans_external_path(ccx, fn_id, tpt.ty)
|
2011-09-16 16:27:34 +02:00
|
|
|
};
|
2012-03-09 10:47:40 +01:00
|
|
|
if tys.len() > 0u {
|
|
|
|
val = PointerCast(bcx, val, T_ptr(type_of_fn_from_ty(
|
|
|
|
ccx, node_id_type(bcx, id))));
|
|
|
|
}
|
2012-02-10 17:46:53 -08:00
|
|
|
|
2012-06-07 14:37:36 -07:00
|
|
|
// FIXME: Need to support external crust functions (#1840)
|
2012-02-10 17:46:53 -08:00
|
|
|
if fn_id.crate == ast::local_crate {
|
2012-02-21 14:20:18 +01:00
|
|
|
alt bcx.tcx().def_map.find(id) {
|
2012-02-10 17:46:53 -08:00
|
|
|
some(ast::def_fn(_, ast::crust_fn)) {
|
|
|
|
// Crust functions are just opaque pointers
|
|
|
|
let val = PointerCast(bcx, val, T_ptr(T_i8()));
|
|
|
|
ret lval_no_env(bcx, val, owned_imm);
|
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 15:05:16 +01:00
|
|
|
ret {bcx: bcx, val: val, kind: owned, env: null_env};
|
2011-01-31 18:06:35 -08:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn lookup_discriminant(ccx: @crate_ctxt, vid: ast::def_id) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("lookup_discriminant");
|
2011-10-14 16:45:25 -07:00
|
|
|
alt ccx.discrims.find(vid) {
|
2012-01-18 22:37:22 -08:00
|
|
|
none {
|
2011-07-27 14:19:39 +02:00
|
|
|
// It's an external discriminant that we haven't seen yet.
|
|
|
|
assert (vid.crate != ast::local_crate);
|
2012-02-03 09:53:37 +01:00
|
|
|
let sym = csearch::get_symbol(ccx.sess.cstore, vid);
|
2012-03-14 15:10:34 -07:00
|
|
|
let gvar = str::as_c_str(sym, {|buf|
|
2012-02-01 11:04:56 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, ccx.int_type, buf)
|
|
|
|
});
|
|
|
|
lib::llvm::SetLinkage(gvar, lib::llvm::ExternalLinkage);
|
2011-07-27 14:19:39 +02:00
|
|
|
llvm::LLVMSetGlobalConstant(gvar, True);
|
2012-02-03 09:53:37 +01:00
|
|
|
ccx.discrims.insert(vid, gvar);
|
2011-07-27 14:19:39 +02:00
|
|
|
ret gvar;
|
|
|
|
}
|
|
|
|
some(llval) { ret llval; }
|
2011-04-07 11:42:40 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 19:49:01 -07:00
|
|
|
fn cast_self(cx: block, slf: val_self_pair) -> ValueRef {
|
2012-05-22 21:44:28 -04:00
|
|
|
PointerCast(cx, slf.v, T_ptr(type_of(cx.ccx(), slf.t)))
|
2012-03-23 19:49:01 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_local_var(cx: block, def: ast::def) -> local_var_result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_local_var");
|
2011-12-10 08:38:40 -08:00
|
|
|
fn take_local(table: hashmap<ast::node_id, local_val>,
|
|
|
|
id: ast::node_id) -> local_var_result {
|
2011-10-07 11:20:51 +02:00
|
|
|
alt table.find(id) {
|
2011-12-10 08:38:40 -08:00
|
|
|
some(local_mem(v)) { {val: v, kind: owned} }
|
|
|
|
some(local_imm(v)) { {val: v, kind: owned_imm} }
|
2012-01-14 16:05:07 -08:00
|
|
|
r { fail("take_local: internal error"); }
|
2011-10-07 11:20:51 +02:00
|
|
|
}
|
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
alt def {
|
2012-02-27 16:05:17 -08:00
|
|
|
ast::def_upvar(nid, _, _) {
|
|
|
|
assert (cx.fcx.llupvars.contains_key(nid));
|
|
|
|
ret { val: cx.fcx.llupvars.get(nid), kind: owned };
|
2011-08-02 15:13:08 -07:00
|
|
|
}
|
2012-02-27 16:05:17 -08:00
|
|
|
ast::def_arg(nid, _) {
|
|
|
|
assert (cx.fcx.llargs.contains_key(nid));
|
|
|
|
ret take_local(cx.fcx.llargs, nid);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-02-28 19:28:29 -08:00
|
|
|
ast::def_local(nid, _) | ast::def_binding(nid) {
|
2012-02-27 16:05:17 -08:00
|
|
|
assert (cx.fcx.lllocals.contains_key(nid));
|
|
|
|
ret take_local(cx.fcx.lllocals, nid);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-05-22 21:44:28 -04:00
|
|
|
ast::def_self(sid) {
|
2012-05-22 05:20:47 -07:00
|
|
|
let slf = alt copy cx.fcx.llself {
|
2012-06-05 15:06:47 -07:00
|
|
|
some(s) { cast_self(cx, s) }
|
2012-05-22 21:44:28 -04:00
|
|
|
none { cx.sess().bug("trans_local_var: reference to self \
|
2012-03-23 19:49:01 -07:00
|
|
|
out of context"); }
|
|
|
|
};
|
2012-05-22 21:44:28 -04:00
|
|
|
ret {val: slf, kind: owned};
|
2011-12-13 13:19:56 +01:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
_ {
|
2012-03-03 17:49:23 -08:00
|
|
|
cx.sess().unimpl(#fmt("unsupported def type in trans_local_def: %?",
|
|
|
|
def));
|
2011-09-01 14:35:00 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-29 12:21:13 -07:00
|
|
|
fn trans_path(cx: block, id: ast::node_id)
|
2011-09-16 16:27:34 +02:00
|
|
|
-> lval_maybe_callee {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_path");
|
2012-03-03 17:49:23 -08:00
|
|
|
alt cx.tcx().def_map.find(id) {
|
|
|
|
none { cx.sess().bug("trans_path: unbound node ID"); }
|
|
|
|
some(df) {
|
2012-03-29 12:21:13 -07:00
|
|
|
ret trans_var(cx, df, id);
|
2012-03-03 17:49:23 -08:00
|
|
|
}
|
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
|
|
|
|
2012-03-29 12:21:13 -07:00
|
|
|
fn trans_var(cx: block, def: ast::def, id: ast::node_id)-> lval_maybe_callee {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_var");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2011-09-01 14:35:00 +02:00
|
|
|
alt def {
|
2012-01-26 10:29:47 +01:00
|
|
|
ast::def_fn(did, _) {
|
2012-03-09 13:35:20 +01:00
|
|
|
ret lval_static_fn(cx, did, id);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
ast::def_variant(tid, vid) {
|
2012-02-14 09:10:47 +01:00
|
|
|
if ty::enum_variant_with_id(ccx.tcx, tid, vid).args.len() > 0u {
|
2011-07-27 14:19:39 +02:00
|
|
|
// N-ary variant.
|
2012-03-09 13:35:20 +01:00
|
|
|
ret lval_static_fn(cx, vid, id);
|
2011-12-14 14:38:25 +01:00
|
|
|
} else {
|
2011-07-27 14:19:39 +02:00
|
|
|
// Nullary variant.
|
2012-02-09 14:33:00 +01:00
|
|
|
let enum_ty = node_id_type(cx, id);
|
2012-06-07 14:37:36 -07:00
|
|
|
let llenumptr = alloc_ty(cx, enum_ty);
|
2012-05-03 22:31:38 -07:00
|
|
|
let lldiscrimptr = GEPi(cx, llenumptr, [0u, 0u]);
|
2012-03-23 14:45:47 +01:00
|
|
|
let lldiscrim_gv = lookup_discriminant(ccx, vid);
|
|
|
|
let lldiscrim = Load(cx, lldiscrim_gv);
|
|
|
|
Store(cx, lldiscrim, lldiscrimptr);
|
|
|
|
ret lval_no_env(cx, llenumptr, temporary);
|
2011-05-12 13:25:18 +02:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-01 14:35:00 +02:00
|
|
|
ast::def_const(did) {
|
2011-07-27 14:19:39 +02:00
|
|
|
if did.crate == ast::local_crate {
|
2012-03-07 12:21:08 +01:00
|
|
|
ret lval_no_env(cx, get_item_val(ccx, did.node), owned);
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
2012-02-09 14:33:00 +01:00
|
|
|
let tp = node_id_type(cx, id);
|
2012-03-09 10:47:40 +01:00
|
|
|
let val = trans_external_path(ccx, did, tp);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(cx, load_if_immediate(cx, val, tp), owned_imm);
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
_ {
|
|
|
|
let loc = trans_local_var(cx, def);
|
2011-12-10 08:38:40 -08:00
|
|
|
ret lval_no_env(cx, loc.val, loc.kind);
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_rec_field(bcx: block, base: @ast::expr,
|
2011-10-05 10:21:57 +02:00
|
|
|
field: ast::ident) -> lval_result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_rec_field");
|
2011-10-05 11:26:27 +02:00
|
|
|
let {bcx, val} = trans_temp_expr(bcx, base);
|
2012-05-14 20:32:29 -07:00
|
|
|
let {bcx, val, ty} = autoderef(bcx, base.id, val, expr_ty(bcx, base));
|
2012-03-23 19:49:01 -07:00
|
|
|
trans_rec_field_inner(bcx, val, ty, field, base.span)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_rec_field_inner(bcx: block, val: ValueRef, ty: ty::t,
|
|
|
|
field: ast::ident, sp: span) -> lval_result {
|
2012-06-05 15:06:47 -07:00
|
|
|
let mut deref = false;
|
2012-02-03 15:15:28 +01:00
|
|
|
let fields = alt ty::get(ty).struct {
|
2012-05-15 17:59:55 -07:00
|
|
|
ty::ty_rec(fs) { fs }
|
|
|
|
ty::ty_class(did, substs) {
|
2012-06-05 15:06:47 -07:00
|
|
|
if option::is_some(ty::ty_dtor(bcx.tcx(), did)) {
|
|
|
|
deref = true;
|
|
|
|
}
|
2012-06-08 14:37:55 -07:00
|
|
|
ty::class_items_as_mutable_fields(bcx.tcx(), did, substs)
|
2012-05-15 17:59:55 -07:00
|
|
|
}
|
|
|
|
// Constraint?
|
|
|
|
_ { bcx.tcx().sess.span_bug(sp, "trans_rec_field:\
|
2012-01-30 21:00:57 -08:00
|
|
|
base expr has non-record type"); }
|
2012-05-15 17:59:55 -07:00
|
|
|
};
|
2012-03-27 22:08:48 -07:00
|
|
|
let ix = field_idx_strict(bcx.tcx(), sp, field, fields);
|
2012-06-05 15:06:47 -07:00
|
|
|
|
|
|
|
/* self is a class with a dtor, which means we
|
|
|
|
have to select out the object itself
|
|
|
|
(If any other code does the same thing, that's
|
|
|
|
a bug */
|
|
|
|
let val = if deref {
|
|
|
|
GEPi(bcx, GEPi(bcx, val, [0u, 1u]), [0u, ix])
|
|
|
|
}
|
|
|
|
else { GEPi(bcx, val, [0u, ix]) };
|
2012-05-22 21:44:28 -04:00
|
|
|
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: val, kind: owned};
|
2010-11-26 15:54:04 -08:00
|
|
|
}
|
|
|
|
|
2012-04-17 15:07:38 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_index(cx: block, ex: @ast::expr, base: @ast::expr,
|
2012-01-26 15:23:04 +01:00
|
|
|
idx: @ast::expr) -> lval_result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_index");
|
2012-02-02 12:37:17 +01:00
|
|
|
let base_ty = expr_ty(cx, base);
|
2011-10-05 11:26:27 +02:00
|
|
|
let exp = trans_temp_expr(cx, base);
|
2012-05-14 20:32:29 -07:00
|
|
|
let lv = autoderef(exp.bcx, base.id, exp.val, base_ty);
|
2011-10-05 11:26:27 +02:00
|
|
|
let ix = trans_temp_expr(lv.bcx, idx);
|
2011-07-27 14:19:39 +02:00
|
|
|
let v = lv.val;
|
|
|
|
let bcx = ix.bcx;
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-10-10 13:32:50 +02:00
|
|
|
// Cast to an LLVM integer. Rust is less strict than LLVM in this regard.
|
2012-02-21 14:20:18 +01:00
|
|
|
let ix_size = llsize_of_real(cx.ccx(), val_ty(ix.val));
|
|
|
|
let int_size = llsize_of_real(cx.ccx(), ccx.int_type);
|
2012-03-15 09:47:03 -04:00
|
|
|
let ix_val = if ix_size < int_size {
|
2012-05-30 17:09:52 -07:00
|
|
|
if ty::type_is_signed(expr_ty(cx, idx)) {
|
|
|
|
SExt(bcx, ix.val, ccx.int_type)
|
|
|
|
} else { ZExt(bcx, ix.val, ccx.int_type) }
|
2011-08-19 15:16:48 -07:00
|
|
|
} else if ix_size > int_size {
|
2012-03-15 09:47:03 -04:00
|
|
|
Trunc(bcx, ix.val, ccx.int_type)
|
|
|
|
} else {
|
|
|
|
ix.val
|
|
|
|
};
|
2011-10-10 13:32:50 +02:00
|
|
|
|
2012-02-02 12:37:17 +01:00
|
|
|
let unit_ty = node_id_type(cx, ex.id);
|
2012-03-12 10:05:15 +01:00
|
|
|
let llunitty = type_of(ccx, unit_ty);
|
|
|
|
let unit_sz = llsize_of(ccx, llunitty);
|
|
|
|
maybe_name_value(cx.ccx(), unit_sz, "unit_sz");
|
|
|
|
let scaled_ix = Mul(bcx, ix_val, unit_sz);
|
2012-02-21 14:20:18 +01:00
|
|
|
maybe_name_value(cx.ccx(), scaled_ix, "scaled_ix");
|
2012-04-09 17:32:49 -07:00
|
|
|
|
2012-04-18 17:02:00 -07:00
|
|
|
let mut (base, len) = tvec::get_base_and_len(bcx, v, base_ty);
|
|
|
|
|
|
|
|
if ty::type_is_str(base_ty) {
|
|
|
|
len = Sub(bcx, len, C_uint(bcx.ccx(), 1u));
|
|
|
|
}
|
2012-04-16 16:17:51 -07:00
|
|
|
|
2012-04-17 15:07:38 -07:00
|
|
|
#debug("trans_index: base %s", val_str(bcx.ccx().tn, base));
|
|
|
|
#debug("trans_index: len %s", val_str(bcx.ccx().tn, len));
|
2012-04-09 17:32:49 -07:00
|
|
|
|
2012-04-17 15:07:38 -07:00
|
|
|
let bounds_check = ICmp(bcx, lib::llvm::IntUGE, scaled_ix, len);
|
2012-03-15 09:47:03 -04:00
|
|
|
let bcx = with_cond(bcx, bounds_check) {|bcx|
|
2012-02-17 13:17:40 +01:00
|
|
|
// fail: bad bounds check.
|
|
|
|
trans_fail(bcx, some(ex.span), "bounds check")
|
|
|
|
};
|
2012-04-17 15:07:38 -07:00
|
|
|
let elt = InBoundsGEP(bcx, base, [ix_val]);
|
2012-03-12 10:05:15 +01:00
|
|
|
ret lval_owned(bcx, PointerCast(bcx, elt, T_ptr(llunitty)));
|
2010-12-10 16:10:35 -08:00
|
|
|
}
|
|
|
|
|
2012-04-13 19:07:47 -07:00
|
|
|
fn expr_is_borrowed(bcx: block, e: @ast::expr) -> bool {
|
|
|
|
bcx.tcx().borrowings.contains_key(e.id)
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn expr_is_lval(bcx: block, e: @ast::expr) -> bool {
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-14 15:21:53 -08:00
|
|
|
ty::expr_is_lval(ccx.maps.method_map, e)
|
2011-12-14 15:23:11 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_callee(bcx: block, e: @ast::expr) -> lval_maybe_callee {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_callee");
|
2011-09-16 16:27:34 +02:00
|
|
|
alt e.node {
|
2012-03-29 12:21:13 -07:00
|
|
|
ast::expr_path(path) { ret trans_path(bcx, e.id); }
|
2012-04-23 09:25:14 +02:00
|
|
|
ast::expr_field(base, _, _) {
|
2011-10-05 11:51:41 +02:00
|
|
|
// Lval means this is a record field, so not a method
|
2011-12-14 15:23:11 +01:00
|
|
|
if !expr_is_lval(bcx, e) {
|
2012-02-14 15:21:53 -08:00
|
|
|
alt bcx.ccx().maps.method_map.find(e.id) {
|
2012-01-26 12:26:14 +01:00
|
|
|
some(origin) { // An impl method
|
2012-01-27 13:17:06 +01:00
|
|
|
ret impl::trans_method_callee(bcx, e.id, base, origin);
|
2012-01-07 22:44:14 +01:00
|
|
|
}
|
2012-02-21 14:25:53 +01:00
|
|
|
_ {
|
|
|
|
bcx.ccx().sess.span_bug(e.span, "trans_callee: weird expr");
|
|
|
|
}
|
2011-12-14 14:38:25 +01:00
|
|
|
}
|
2011-10-05 10:21:57 +02:00
|
|
|
}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2011-10-05 10:21:57 +02:00
|
|
|
_ {}
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
2011-10-05 11:51:41 +02:00
|
|
|
let lv = trans_temp_lval(bcx, e);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret lval_no_env(lv.bcx, lv.val, lv.kind);
|
2011-09-16 16:27:34 +02:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Use this when you know you are compiling an lval.
|
2010-12-07 11:57:19 -08:00
|
|
|
// The additional bool returned indicates whether it's mem (that is
|
|
|
|
// represented as an alloca or heap, hence needs a 'load' to be used as an
|
|
|
|
// immediate).
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_lval(cx: block, e: @ast::expr) -> lval_result {
|
2012-05-14 20:32:29 -07:00
|
|
|
ret alt cx.ccx().maps.root_map.find({id:e.id, derefs:0u}) {
|
|
|
|
// No need to root this lvalue.
|
|
|
|
none { unrooted(cx, e) }
|
|
|
|
|
|
|
|
// Lvalue must remain rooted until exit of `scope_id`. See
|
|
|
|
// add_root_cleanup() for comments on why this works the way it does.
|
|
|
|
some(scope_id) {
|
|
|
|
let lv = unrooted(cx, e);
|
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if !cx.sess().no_asm_comments() {
|
2012-05-14 20:32:29 -07:00
|
|
|
add_comment(cx, #fmt["preserving until end of scope %d",
|
|
|
|
scope_id]);
|
|
|
|
}
|
|
|
|
|
2012-06-08 05:46:29 -07:00
|
|
|
let _icx = lv.bcx.insn_ctxt("root_value_lval");
|
2012-05-14 20:32:29 -07:00
|
|
|
let ty = expr_ty(lv.bcx, e);
|
2012-05-28 20:52:11 -07:00
|
|
|
let root_loc = alloca_zeroed(lv.bcx, type_of(cx.ccx(), ty));
|
2012-05-14 20:32:29 -07:00
|
|
|
let bcx = store_temp_expr(lv.bcx, INIT, root_loc, lv, ty, false);
|
|
|
|
add_root_cleanup(bcx, scope_id, root_loc, ty);
|
|
|
|
{bcx: bcx with lv}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-05-14 20:32:29 -07:00
|
|
|
};
|
|
|
|
|
|
|
|
fn unrooted(cx: block, e: @ast::expr) -> lval_result {
|
|
|
|
let _icx = cx.insn_ctxt("trans_lval");
|
|
|
|
alt e.node {
|
|
|
|
ast::expr_path(_) {
|
|
|
|
let v = trans_path(cx, e.id);
|
|
|
|
ret lval_maybe_callee_to_lval(v, expr_ty(cx, e));
|
|
|
|
}
|
|
|
|
ast::expr_field(base, ident, _) {
|
|
|
|
ret trans_rec_field(cx, base, ident);
|
|
|
|
}
|
|
|
|
ast::expr_index(base, idx) {
|
|
|
|
ret trans_index(cx, e, base, idx);
|
|
|
|
}
|
|
|
|
ast::expr_unary(ast::deref, base) {
|
|
|
|
let ccx = cx.ccx();
|
|
|
|
let sub = trans_temp_expr(cx, base);
|
|
|
|
let t = expr_ty(cx, base);
|
|
|
|
let val = alt check ty::get(t).struct {
|
|
|
|
ty::ty_box(_) {
|
2012-06-12 16:41:20 -07:00
|
|
|
let non_gc_val = non_gc_box_cast(sub.bcx, sub.val);
|
2012-05-14 20:32:29 -07:00
|
|
|
GEPi(sub.bcx, non_gc_val, [0u, abi::box_field_body])
|
|
|
|
}
|
2012-05-09 14:11:46 -07:00
|
|
|
ty::ty_uniq(_) {
|
2012-06-12 16:41:20 -07:00
|
|
|
let non_gc_val = non_gc_box_cast(sub.bcx, sub.val);
|
2012-06-04 22:56:40 -07:00
|
|
|
GEPi(sub.bcx, non_gc_val, [0u, abi::box_field_body])
|
2012-05-09 14:11:46 -07:00
|
|
|
}
|
2012-05-14 20:32:29 -07:00
|
|
|
ty::ty_res(_, _, _) {
|
|
|
|
GEPi(sub.bcx, sub.val, [0u, 1u])
|
|
|
|
}
|
|
|
|
ty::ty_enum(_, _) {
|
|
|
|
let ety = expr_ty(cx, e);
|
|
|
|
let ellty = T_ptr(type_of(ccx, ety));
|
|
|
|
PointerCast(sub.bcx, sub.val, ellty)
|
|
|
|
}
|
2012-05-09 14:11:46 -07:00
|
|
|
ty::ty_ptr(_) | ty::ty_rptr(_,_) { sub.val }
|
2012-05-14 20:32:29 -07:00
|
|
|
};
|
|
|
|
ret lval_owned(sub.bcx, val);
|
|
|
|
}
|
|
|
|
_ { cx.sess().span_bug(e.span, "non-lval in trans_lval"); }
|
|
|
|
}
|
2011-07-08 14:28:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-07 14:27:43 -07:00
|
|
|
#[doc = "
|
|
|
|
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.
|
|
|
|
"]
|
2012-06-12 16:41:20 -07:00
|
|
|
fn non_gc_box_cast(cx: block, val: ValueRef) -> ValueRef {
|
2012-05-07 14:27:43 -07:00
|
|
|
#debug("non_gc_box_cast");
|
|
|
|
add_comment(cx, "non_gc_box_cast");
|
2012-06-12 16:41:20 -07:00
|
|
|
assert(llvm::LLVMGetPointerAddressSpace(val_ty(val)) as uint == 1u);
|
|
|
|
let non_gc_t = T_ptr(llvm::LLVMGetElementType(val_ty(val)));
|
2012-05-07 14:27:43 -07:00
|
|
|
PointerCast(cx, val, non_gc_t)
|
|
|
|
}
|
|
|
|
|
2011-09-16 16:27:34 +02:00
|
|
|
fn lval_maybe_callee_to_lval(c: lval_maybe_callee, ty: ty::t) -> lval_result {
|
2012-03-16 12:57:07 +01:00
|
|
|
let must_bind = alt c.env { self_env(_, _, _) { true } _ { false } };
|
2012-02-14 10:47:39 +01:00
|
|
|
if must_bind {
|
2012-02-14 09:10:47 +01:00
|
|
|
let n_args = ty::ty_fn_args(ty).len();
|
2012-03-12 15:52:30 -07:00
|
|
|
let args = vec::from_elem(n_args, none);
|
2011-09-28 15:57:38 +02:00
|
|
|
let space = alloc_ty(c.bcx, ty);
|
2012-03-23 14:45:47 +01:00
|
|
|
let bcx = closure::trans_bind_1(c.bcx, ty, c, args, ty,
|
|
|
|
save_in(space));
|
|
|
|
add_clean_temp(bcx, space, ty);
|
|
|
|
{bcx: bcx, val: space, kind: temporary}
|
2012-02-14 10:47:39 +01:00
|
|
|
} else {
|
2012-02-15 15:42:35 +01:00
|
|
|
alt check c.env {
|
2012-02-14 10:47:39 +01:00
|
|
|
is_closure { {bcx: c.bcx, val: c.val, kind: c.kind} }
|
|
|
|
null_env {
|
|
|
|
let llfnty = llvm::LLVMGetElementType(val_ty(c.val));
|
|
|
|
let llfn = create_real_fn_pair(c.bcx, llfnty, c.val,
|
|
|
|
null_env_ptr(c.bcx));
|
|
|
|
{bcx: c.bcx, val: llfn, kind: temporary}
|
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn int_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llsrc: ValueRef, signed: bool) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("int_cast");
|
2011-07-27 14:19:39 +02:00
|
|
|
let srcsz = llvm::LLVMGetIntTypeWidth(llsrctype);
|
|
|
|
let dstsz = llvm::LLVMGetIntTypeWidth(lldsttype);
|
|
|
|
ret if dstsz == srcsz {
|
2012-05-14 20:32:29 -07:00
|
|
|
BitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else if srcsz > dstsz {
|
|
|
|
TruncOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else if signed {
|
|
|
|
SExtOrBitCast(bcx, llsrc, lldsttype)
|
|
|
|
} else { ZExtOrBitCast(bcx, llsrc, lldsttype) };
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn float_cast(bcx: block, lldsttype: TypeRef, llsrctype: TypeRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llsrc: ValueRef) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("float_cast");
|
2011-07-27 14:19:39 +02:00
|
|
|
let srcsz = lib::llvm::float_width(llsrctype);
|
|
|
|
let dstsz = lib::llvm::float_width(lldsttype);
|
|
|
|
ret if dstsz > srcsz {
|
2012-05-14 20:32:29 -07:00
|
|
|
FPExt(bcx, llsrc, lldsttype)
|
|
|
|
} else if srcsz > dstsz {
|
|
|
|
FPTrunc(bcx, llsrc, lldsttype)
|
|
|
|
} else { llsrc };
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
|
2012-03-14 18:04:03 +01:00
|
|
|
enum cast_kind { cast_pointer, cast_integral, cast_float,
|
2012-05-14 20:32:29 -07:00
|
|
|
cast_enum, cast_other, }
|
2012-03-14 18:04:03 +01:00
|
|
|
fn cast_type_kind(t: ty::t) -> cast_kind {
|
2012-05-18 19:05:31 -07:00
|
|
|
alt ty::get(t).struct {
|
|
|
|
ty::ty_float(*) {cast_float}
|
|
|
|
ty::ty_ptr(*) {cast_pointer}
|
|
|
|
ty::ty_rptr(*) {cast_pointer}
|
|
|
|
ty::ty_int(*) {cast_integral}
|
|
|
|
ty::ty_uint(*) {cast_integral}
|
|
|
|
ty::ty_bool {cast_integral}
|
|
|
|
ty::ty_enum(*) {cast_enum}
|
|
|
|
_ {cast_other}
|
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_cast(cx: block, e: @ast::expr, id: ast::node_id,
|
|
|
|
dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_cast");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-02-02 12:37:17 +01:00
|
|
|
let t_out = node_id_type(cx, id);
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(t_out).struct {
|
2012-01-27 13:17:06 +01:00
|
|
|
ty::ty_iface(_, _) { ret impl::trans_cast(cx, e, id, dest); }
|
2012-01-07 22:44:14 +01:00
|
|
|
_ {}
|
|
|
|
}
|
2011-10-05 11:26:27 +02:00
|
|
|
let e_res = trans_temp_expr(cx, e);
|
2011-07-27 14:19:39 +02:00
|
|
|
let ll_t_in = val_ty(e_res.val);
|
2012-02-02 12:37:17 +01:00
|
|
|
let t_in = expr_ty(cx, e);
|
2012-01-27 12:55:21 +01:00
|
|
|
let ll_t_out = type_of(ccx, t_out);
|
2011-07-22 13:10:59 +02:00
|
|
|
|
2012-03-14 18:04:03 +01:00
|
|
|
let k_in = cast_type_kind(t_in);
|
|
|
|
let k_out = cast_type_kind(t_out);
|
|
|
|
let s_in = k_in == cast_integral && ty::type_is_signed(t_in);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
|
|
|
let newval =
|
|
|
|
alt {in: k_in, out: k_out} {
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_integral, out: cast_integral} {
|
2011-07-27 14:19:39 +02:00
|
|
|
int_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val, s_in)
|
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_float, out: cast_float} {
|
2011-07-27 14:19:39 +02:00
|
|
|
float_cast(e_res.bcx, ll_t_out, ll_t_in, e_res.val)
|
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_integral, out: cast_float} {
|
2011-07-27 14:19:39 +02:00
|
|
|
if s_in {
|
2011-08-30 09:59:30 +02:00
|
|
|
SIToFP(e_res.bcx, e_res.val, ll_t_out)
|
|
|
|
} else { UIToFP(e_res.bcx, e_res.val, ll_t_out) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_float, out: cast_integral} {
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_signed(t_out) {
|
2011-08-30 09:59:30 +02:00
|
|
|
FPToSI(e_res.bcx, e_res.val, ll_t_out)
|
|
|
|
} else { FPToUI(e_res.bcx, e_res.val, ll_t_out) }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_integral, out: cast_pointer} {
|
2011-08-30 09:59:30 +02:00
|
|
|
IntToPtr(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_pointer, out: cast_integral} {
|
2011-08-30 09:59:30 +02:00
|
|
|
PtrToInt(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_pointer, out: cast_pointer} {
|
2011-08-30 09:59:30 +02:00
|
|
|
PointerCast(e_res.bcx, e_res.val, ll_t_out)
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
{in: cast_enum, out: cast_integral} |
|
|
|
|
{in: cast_enum, out: cast_float} {
|
2012-01-10 14:55:54 -07:00
|
|
|
let cx = e_res.bcx;
|
2012-01-25 14:34:31 +01:00
|
|
|
let llenumty = T_opaque_enum_ptr(ccx);
|
|
|
|
let av_enum = PointerCast(cx, e_res.val, llenumty);
|
2012-05-03 22:31:38 -07:00
|
|
|
let lldiscrim_a_ptr = GEPi(cx, av_enum, [0u, 0u]);
|
2012-01-10 14:55:54 -07:00
|
|
|
let lldiscrim_a = Load(cx, lldiscrim_a_ptr);
|
|
|
|
alt k_out {
|
2012-03-14 18:04:03 +01:00
|
|
|
cast_integral {int_cast(e_res.bcx, ll_t_out,
|
|
|
|
val_ty(lldiscrim_a), lldiscrim_a, true)}
|
|
|
|
cast_float {SIToFP(e_res.bcx, lldiscrim_a, ll_t_out)}
|
2012-03-05 16:27:27 -08:00
|
|
|
_ { ccx.sess.bug("translating unsupported cast.") }
|
2012-01-10 14:55:54 -07:00
|
|
|
}
|
|
|
|
}
|
2012-03-05 16:27:27 -08:00
|
|
|
_ { ccx.sess.bug("translating unsupported cast.") }
|
2011-07-27 14:19:39 +02:00
|
|
|
};
|
2011-09-29 10:46:49 +02:00
|
|
|
ret store_in_dest(e_res.bcx, newval, dest);
|
2010-11-24 10:32:14 -08:00
|
|
|
}
|
|
|
|
|
2012-03-27 12:33:13 +02:00
|
|
|
fn trans_loop_body(bcx: block, e: @ast::expr, ret_flag: option<ValueRef>,
|
|
|
|
dest: dest) -> block {
|
|
|
|
alt check e.node {
|
2012-05-04 12:33:04 -07:00
|
|
|
ast::expr_loop_body(b@@{node: ast::expr_fn_block(decl, body, cap), _}) {
|
2012-03-27 12:33:13 +02:00
|
|
|
alt check ty::get(expr_ty(bcx, e)).struct {
|
|
|
|
ty::ty_fn({proto, _}) {
|
2012-06-01 19:47:04 -07:00
|
|
|
closure::trans_expr_fn(bcx, proto, decl, body, b.id,
|
2012-05-04 12:33:04 -07:00
|
|
|
cap, some(ret_flag),
|
2012-03-27 12:33:13 +02:00
|
|
|
dest)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-24 17:45:16 -08:00
|
|
|
// temp_cleanups: cleanups that should run only if failure occurs before the
|
|
|
|
// call takes place:
|
|
|
|
fn trans_arg_expr(cx: block, arg: ty::arg, lldestty: TypeRef, e: @ast::expr,
|
2012-03-27 12:33:13 +02:00
|
|
|
&temp_cleanups: [ValueRef], ret_flag: option<ValueRef>)
|
|
|
|
-> result {
|
2012-04-17 15:07:38 -07:00
|
|
|
#debug("+++ trans_arg_expr on %s", expr_to_str(e));
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_arg_expr");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-02-02 12:37:17 +01:00
|
|
|
let e_ty = expr_ty(cx, e);
|
2012-02-03 15:15:28 +01:00
|
|
|
let is_bot = ty::type_is_bot(e_ty);
|
2012-03-27 12:33:13 +02:00
|
|
|
let lv = alt ret_flag {
|
|
|
|
// If there is a ret_flag, this *must* be a loop body
|
|
|
|
some(ptr) {
|
|
|
|
alt check e.node {
|
|
|
|
ast::expr_loop_body(blk) {
|
|
|
|
let scratch = alloc_ty(cx, expr_ty(cx, blk));
|
|
|
|
let bcx = trans_loop_body(cx, e, ret_flag, save_in(scratch));
|
|
|
|
{bcx: bcx, val: scratch, kind: temporary}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
none { trans_temp_lval(cx, e) }
|
|
|
|
};
|
2012-04-20 12:11:55 -07:00
|
|
|
#debug(" pre-adaptation value: %s", val_str(lv.bcx.ccx().tn, lv.val));
|
2012-06-01 21:54:38 -07:00
|
|
|
let {lv, arg} = adapt_borrowed_value(lv, arg, e);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = lv.bcx;
|
|
|
|
let mut val = lv.val;
|
2012-04-17 15:07:38 -07:00
|
|
|
#debug(" adapted value: %s", val_str(bcx.ccx().tn, val));
|
2012-02-02 16:50:17 -08:00
|
|
|
let arg_mode = ty::resolved_mode(ccx.tcx, arg.mode);
|
2011-07-27 14:19:39 +02:00
|
|
|
if is_bot {
|
2011-06-02 17:50:37 -07:00
|
|
|
// For values of type _|_, we generate an
|
|
|
|
// "undef" value, as such a value should never
|
|
|
|
// be inspected. It's important for the value
|
2012-01-09 17:44:55 +01:00
|
|
|
// to have type lldestty (the callee's expected type).
|
|
|
|
val = llvm::LLVMGetUndef(lldestty);
|
2012-02-02 16:50:17 -08:00
|
|
|
} else if arg_mode == ast::by_ref || arg_mode == ast::by_val {
|
2012-04-17 15:07:38 -07:00
|
|
|
let imm = ty::type_is_immediate(arg.ty);
|
2012-06-01 21:54:38 -07:00
|
|
|
#debug[" arg.ty=%s, imm=%b, arg_mode=%?, lv.kind=%?",
|
|
|
|
ty_to_str(bcx.tcx(), arg.ty), imm, arg_mode, lv.kind];
|
2012-02-02 16:50:17 -08:00
|
|
|
if arg_mode == ast::by_ref && lv.kind != owned && imm {
|
2011-09-07 15:13:19 +02:00
|
|
|
val = do_spill_noroot(bcx, val);
|
2011-07-07 16:14:00 +02:00
|
|
|
}
|
2012-02-02 16:50:17 -08:00
|
|
|
if arg_mode == ast::by_val && (lv.kind == owned || !imm) {
|
2011-10-06 14:17:56 +02:00
|
|
|
val = Load(bcx, val);
|
|
|
|
}
|
2012-02-16 13:07:53 +01:00
|
|
|
} else if arg_mode == ast::by_copy || arg_mode == ast::by_move {
|
2012-04-17 15:07:38 -07:00
|
|
|
let alloc = alloc_ty(bcx, arg.ty);
|
2012-02-16 13:07:53 +01:00
|
|
|
let move_out = arg_mode == ast::by_move ||
|
2012-05-25 00:14:40 -07:00
|
|
|
ccx.maps.last_use_map.contains_key(e.id);
|
2011-11-16 12:32:38 +01:00
|
|
|
if lv.kind == temporary { revoke_clean(bcx, val); }
|
2012-04-17 15:07:38 -07:00
|
|
|
if lv.kind == owned || !ty::type_is_immediate(arg.ty) {
|
|
|
|
memmove_ty(bcx, alloc, val, arg.ty);
|
|
|
|
if move_out && ty::type_needs_drop(ccx.tcx, arg.ty) {
|
2012-05-28 20:52:11 -07:00
|
|
|
bcx = zero_mem(bcx, val, arg.ty);
|
2011-11-18 16:43:30 +01:00
|
|
|
}
|
2011-11-16 12:32:38 +01:00
|
|
|
} else { Store(bcx, val, alloc); }
|
|
|
|
val = alloc;
|
2012-02-16 13:07:53 +01:00
|
|
|
if lv.kind != temporary && !move_out {
|
2012-04-17 15:07:38 -07:00
|
|
|
bcx = take_ty(bcx, val, arg.ty);
|
2011-11-18 16:43:30 +01:00
|
|
|
}
|
2012-02-24 17:45:16 -08:00
|
|
|
|
|
|
|
// In the event that failure occurs before the call actually
|
|
|
|
// happens, have to cleanup this copy:
|
2012-04-17 15:07:38 -07:00
|
|
|
add_clean_temp_mem(bcx, val, arg.ty);
|
2012-02-24 17:45:16 -08:00
|
|
|
temp_cleanups += [val];
|
2012-04-17 15:07:38 -07:00
|
|
|
} else if ty::type_is_immediate(arg.ty) && lv.kind != owned {
|
|
|
|
val = do_spill(bcx, val, arg.ty);
|
2011-07-07 16:14:00 +02:00
|
|
|
}
|
|
|
|
|
2012-02-07 11:25:04 +01:00
|
|
|
if !is_bot && arg.ty != e_ty || ty::type_has_params(arg.ty) {
|
2012-04-20 12:11:55 -07:00
|
|
|
#debug(" casting from %s", val_str(bcx.ccx().tn, val));
|
2011-08-30 09:59:30 +02:00
|
|
|
val = PointerCast(bcx, val, lldestty);
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
2012-04-17 15:07:38 -07:00
|
|
|
#debug("--- trans_arg_expr passing %s", val_str(bcx.ccx().tn, val));
|
2011-06-24 19:04:08 +02:00
|
|
|
ret rslt(bcx, val);
|
2011-04-23 14:17:44 -07:00
|
|
|
}
|
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
fn load_value_from_lval_result(lv: lval_result) -> ValueRef {
|
|
|
|
alt lv.kind {
|
|
|
|
temporary { lv.val }
|
|
|
|
owned { Load(lv.bcx, lv.val) }
|
|
|
|
owned_imm { lv.val }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-06-01 21:54:38 -07:00
|
|
|
// when invoking a method, an argument of type @T or ~T can be implicltly
|
|
|
|
// converted to an argument of type &T. Similarly, [T] can be converted to
|
|
|
|
// [T]/& and so on. If such a conversion (called borrowing) is necessary,
|
|
|
|
// then the borrowings table will have an appropriate entry inserted. This
|
|
|
|
// routine consults this table and performs these adaptations. It returns a
|
|
|
|
// new location for the borrowed result as well as a new type for the argument
|
|
|
|
// that reflects the borrowed value and not the original.
|
|
|
|
fn adapt_borrowed_value(lv: lval_result, arg: ty::arg,
|
|
|
|
e: @ast::expr) -> {lv: lval_result,
|
|
|
|
arg: ty::arg} {
|
2012-04-13 19:07:47 -07:00
|
|
|
let bcx = lv.bcx;
|
2012-06-01 21:54:38 -07:00
|
|
|
if !expr_is_borrowed(bcx, e) {
|
|
|
|
ret {lv:lv, arg:arg};
|
|
|
|
}
|
2012-04-13 19:07:47 -07:00
|
|
|
|
|
|
|
let e_ty = expr_ty(bcx, e);
|
|
|
|
alt ty::get(e_ty).struct {
|
2012-06-01 21:54:38 -07:00
|
|
|
ty::ty_uniq(mt) | ty::ty_box(mt) {
|
2012-05-14 20:32:29 -07:00
|
|
|
let box_ptr = load_value_from_lval_result(lv);
|
2012-05-03 22:31:38 -07:00
|
|
|
let body_ptr = GEPi(bcx, box_ptr, [0u, abi::box_field_body]);
|
2012-06-01 21:54:38 -07:00
|
|
|
let rptr_ty = ty::mk_rptr(bcx.tcx(), ty::re_static, mt);
|
|
|
|
ret {lv: lval_temp(bcx, body_ptr),
|
|
|
|
arg: {ty: rptr_ty with arg}};
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
|
|
|
|
2012-04-17 15:07:38 -07:00
|
|
|
ty::ty_str | ty::ty_vec(_) |
|
|
|
|
ty::ty_estr(_) |
|
|
|
|
ty::ty_evec(_, _) {
|
|
|
|
let ccx = bcx.ccx();
|
2012-04-20 12:11:55 -07:00
|
|
|
let val = alt lv.kind {
|
|
|
|
temporary { lv.val }
|
|
|
|
owned { load_if_immediate(bcx, lv.val, e_ty) }
|
|
|
|
owned_imm { lv.val }
|
|
|
|
};
|
|
|
|
|
2012-04-17 15:07:38 -07:00
|
|
|
let unit_ty = ty::sequence_element_type(ccx.tcx, e_ty);
|
|
|
|
let llunit_ty = type_of(ccx, unit_ty);
|
2012-04-20 12:11:55 -07:00
|
|
|
let (base, len) = tvec::get_base_and_len(bcx, val, e_ty);
|
2012-04-17 15:07:38 -07:00
|
|
|
let p = alloca(bcx, T_struct([T_ptr(llunit_ty), ccx.int_type]));
|
2012-04-20 12:11:55 -07:00
|
|
|
|
|
|
|
#debug("adapt_borrowed_value: adapting %s to %s",
|
|
|
|
val_str(bcx.ccx().tn, val),
|
|
|
|
val_str(bcx.ccx().tn, p));
|
|
|
|
|
2012-05-03 22:31:38 -07:00
|
|
|
Store(bcx, base, GEPi(bcx, p, [0u, abi::slice_elt_base]));
|
|
|
|
Store(bcx, len, GEPi(bcx, p, [0u, abi::slice_elt_len]));
|
2012-06-01 21:54:38 -07:00
|
|
|
|
|
|
|
// this isn't necessarily the type that rust would assign but it's
|
|
|
|
// close enough for trans purposes, as it will have the same runtime
|
|
|
|
// representation
|
|
|
|
let slice_ty = ty::mk_evec(bcx.tcx(),
|
|
|
|
{ty: unit_ty, mutbl: ast::m_imm},
|
|
|
|
ty::vstore_slice(ty::re_static));
|
|
|
|
|
|
|
|
ret {lv: lval_temp(bcx, p),
|
|
|
|
arg: {ty: slice_ty with arg}};
|
2012-04-13 19:07:47 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
_ {
|
|
|
|
bcx.tcx().sess.span_bug(
|
|
|
|
e.span, #fmt["cannot borrow a value of type %s",
|
|
|
|
ty_to_str(bcx.tcx(), e_ty)]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 15:16:46 -04:00
|
|
|
enum call_args {
|
|
|
|
arg_exprs([@ast::expr]),
|
|
|
|
arg_vals([ValueRef])
|
|
|
|
}
|
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 15:16:46 -04:00
|
|
|
fn trans_args(cx: block, llenv: ValueRef, args: call_args, fn_ty: ty::t,
|
2012-03-27 12:33:13 +02:00
|
|
|
dest: dest, ret_flag: option<ValueRef>)
|
2012-03-09 17:55:39 +01:00
|
|
|
-> {bcx: block, args: [ValueRef], retslot: ValueRef} {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_args");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut temp_cleanups = [];
|
2012-03-14 15:16:46 -04:00
|
|
|
let arg_tys = ty::ty_fn_args(fn_ty);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut llargs: [ValueRef] = [];
|
2011-08-09 17:56:26 -07:00
|
|
|
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = cx.ccx();
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = cx;
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2012-03-08 19:02:22 +01:00
|
|
|
let retty = ty::ty_fn_ret(fn_ty);
|
2011-09-21 12:40:27 +02:00
|
|
|
// Arg 0: Output pointer.
|
2011-11-23 10:56:10 +01:00
|
|
|
let llretslot = alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2012-03-23 15:05:16 +01:00
|
|
|
if ty::type_is_nil(retty) {
|
2012-01-05 22:45:02 +01:00
|
|
|
llvm::LLVMGetUndef(T_ptr(T_nil()))
|
2012-03-23 14:45:47 +01:00
|
|
|
} else { alloc_ty(bcx, retty) }
|
2011-11-23 10:56:10 +01:00
|
|
|
}
|
|
|
|
save_in(dst) { dst }
|
2012-03-23 14:45:47 +01:00
|
|
|
by_val(_) { alloc_ty(bcx, retty) }
|
2011-10-05 10:21:40 +02:00
|
|
|
};
|
|
|
|
|
2012-03-08 19:02:22 +01:00
|
|
|
llargs += [llretslot];
|
2011-02-08 11:47:53 -08:00
|
|
|
|
2012-01-13 10:58:31 +01:00
|
|
|
// Arg 1: Env (closure-bindings / self value)
|
2011-10-14 15:16:44 -07:00
|
|
|
llargs += [llenv];
|
2011-02-08 11:47:53 -08:00
|
|
|
|
|
|
|
// ... then explicit args.
|
2011-02-24 13:51:53 -08:00
|
|
|
|
|
|
|
// First we figure out the caller's view of the types of the arguments.
|
|
|
|
// This will be needed if this is a generic call, because the callee has
|
|
|
|
// to cast her view of the arguments to the caller's view.
|
2012-03-14 15:16:46 -04:00
|
|
|
alt args {
|
|
|
|
arg_exprs(es) {
|
|
|
|
let llarg_tys = type_of_explicit_args(ccx, arg_tys);
|
2012-03-27 12:33:13 +02:00
|
|
|
let last = es.len() - 1u;
|
|
|
|
vec::iteri(es) {|i, e|
|
2012-03-14 15:16:46 -04:00
|
|
|
let r = trans_arg_expr(bcx, arg_tys[i], llarg_tys[i],
|
2012-03-27 12:33:13 +02:00
|
|
|
e, temp_cleanups, if i == last { ret_flag }
|
2012-05-14 20:32:29 -07:00
|
|
|
else { none });
|
2012-03-14 15:16:46 -04:00
|
|
|
bcx = r.bcx;
|
|
|
|
llargs += [r.val];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
arg_vals(vs) {
|
|
|
|
llargs += vs;
|
|
|
|
}
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
2012-02-24 17:45:16 -08:00
|
|
|
|
|
|
|
// now that all arguments have been successfully built, we can revoke any
|
|
|
|
// temporary cleanups, as they are only needed if argument construction
|
|
|
|
// should fail (for example, cleanup of copy mode args).
|
|
|
|
vec::iter(temp_cleanups) {|c|
|
|
|
|
revoke_clean(bcx, c)
|
|
|
|
}
|
|
|
|
|
2011-08-19 15:16:48 -07:00
|
|
|
ret {bcx: bcx,
|
|
|
|
args: llargs,
|
2012-02-16 13:07:53 +01:00
|
|
|
retslot: llretslot};
|
2011-02-08 11:47:53 -08:00
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn trans_call(in_cx: block, call_ex: @ast::expr, f: @ast::expr,
|
2012-03-14 15:16:46 -04:00
|
|
|
args: call_args, id: ast::node_id, dest: dest)
|
2012-02-17 13:17:40 +01:00
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = in_cx.insn_ctxt("trans_call");
|
2012-05-14 14:24:16 -07:00
|
|
|
trans_call_inner(
|
|
|
|
in_cx, call_ex.info(), expr_ty(in_cx, f), node_id_type(in_cx, id),
|
|
|
|
{|cx| trans_callee(cx, f)}, args, dest)
|
2012-01-26 12:26:14 +01:00
|
|
|
}
|
|
|
|
|
2012-03-27 12:33:13 +02:00
|
|
|
fn body_contains_ret(body: ast::blk) -> bool {
|
|
|
|
let cx = {mut found: false};
|
|
|
|
visit::visit_block(body, cx, visit::mk_vt(@{
|
|
|
|
visit_item: {|_i, _cx, _v|},
|
|
|
|
visit_expr: {|e: @ast::expr, cx: {mut found: bool}, v|
|
|
|
|
if !cx.found {
|
|
|
|
alt e.node {
|
|
|
|
ast::expr_ret(_) { cx.found = true; }
|
|
|
|
_ { visit::visit_expr(e, cx, v); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} with *visit::default_visitor()
|
|
|
|
}));
|
|
|
|
cx.found
|
|
|
|
}
|
|
|
|
|
2012-06-12 14:55:44 -07:00
|
|
|
// See [Note-arg-mode]
|
2012-05-14 14:24:16 -07:00
|
|
|
fn trans_call_inner(
|
2012-06-12 14:55:44 -07:00
|
|
|
++in_cx: block,
|
2012-05-14 14:24:16 -07:00
|
|
|
call_info: option<node_info>,
|
|
|
|
fn_expr_ty: ty::t,
|
|
|
|
ret_ty: ty::t,
|
|
|
|
get_callee: fn(block) -> lval_maybe_callee,
|
|
|
|
args: call_args,
|
|
|
|
dest: dest) -> block {
|
|
|
|
|
|
|
|
with_scope(in_cx, call_info, "call") {|cx|
|
|
|
|
let ret_in_loop = alt args {
|
|
|
|
arg_exprs(args) { args.len() > 0u && alt vec::last(args).node {
|
|
|
|
ast::expr_loop_body(@{node: ast::expr_fn_block(_, body, _), _}) {
|
|
|
|
body_contains_ret(body)
|
|
|
|
}
|
|
|
|
_ { false }
|
|
|
|
} }
|
|
|
|
_ { false }
|
|
|
|
};
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
let f_res = get_callee(cx);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = f_res.bcx;
|
|
|
|
let ccx = cx.ccx();
|
2012-03-27 12:33:13 +02:00
|
|
|
let ret_flag = if ret_in_loop {
|
2012-04-18 13:00:18 +02:00
|
|
|
let flag = alloca(bcx, T_bool());
|
|
|
|
Store(bcx, C_bool(false), flag);
|
2012-03-27 12:33:13 +02:00
|
|
|
some(flag)
|
|
|
|
} else { none };
|
2012-02-17 13:17:40 +01:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut faddr = f_res.val;
|
2012-03-08 16:10:25 +01:00
|
|
|
let llenv = alt f_res.env {
|
2012-02-17 13:17:40 +01:00
|
|
|
null_env {
|
2012-03-08 16:10:25 +01:00
|
|
|
llvm::LLVMGetUndef(T_opaque_box_ptr(ccx))
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
2012-03-16 12:57:07 +01:00
|
|
|
self_env(e, _, _) {
|
2012-03-08 16:10:25 +01:00
|
|
|
PointerCast(bcx, e, T_opaque_box_ptr(ccx))
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
|
|
|
is_closure {
|
|
|
|
// It's a closure. Have to fetch the elements
|
|
|
|
if f_res.kind == owned {
|
|
|
|
faddr = load_if_immediate(bcx, faddr, fn_expr_ty);
|
|
|
|
}
|
|
|
|
let pair = faddr;
|
2012-05-03 22:31:38 -07:00
|
|
|
faddr = GEPi(bcx, pair, [0u, abi::fn_field_code]);
|
2012-02-17 13:17:40 +01:00
|
|
|
faddr = Load(bcx, faddr);
|
2012-05-03 22:31:38 -07:00
|
|
|
let llclosure = GEPi(bcx, pair, [0u, abi::fn_field_box]);
|
2012-03-08 16:10:25 +01:00
|
|
|
Load(bcx, llclosure)
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
2012-03-08 16:10:25 +01:00
|
|
|
};
|
2011-08-09 17:56:26 -07:00
|
|
|
|
2012-03-14 15:16:46 -04:00
|
|
|
let args_res = {
|
2012-03-27 12:33:13 +02:00
|
|
|
trans_args(bcx, llenv, args, fn_expr_ty, dest, ret_flag)
|
2012-03-14 15:16:46 -04:00
|
|
|
};
|
2012-02-17 13:17:40 +01:00
|
|
|
bcx = args_res.bcx;
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut llargs = args_res.args;
|
2012-03-09 11:43:46 +01:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
let llretslot = args_res.retslot;
|
|
|
|
|
|
|
|
/* If the block is terminated,
|
|
|
|
then one or more of the args has
|
|
|
|
type _|_. Since that means it diverges, the code
|
|
|
|
for the call itself is unreachable. */
|
2012-03-26 12:45:02 -07:00
|
|
|
bcx = invoke(bcx, faddr, llargs);
|
2012-02-17 13:17:40 +01:00
|
|
|
alt dest {
|
|
|
|
ignore {
|
|
|
|
if llvm::LLVMIsUndef(llretslot) != lib::llvm::True {
|
|
|
|
bcx = drop_ty(bcx, llretslot, ret_ty);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
save_in(_) { } // Already saved by callee
|
|
|
|
by_val(cell) {
|
|
|
|
*cell = Load(bcx, llretslot);
|
|
|
|
}
|
|
|
|
}
|
2012-03-27 12:33:13 +02:00
|
|
|
if ty::type_is_bot(ret_ty) {
|
|
|
|
Unreachable(bcx);
|
|
|
|
} else if ret_in_loop {
|
|
|
|
bcx = with_cond(bcx, Load(bcx, option::get(ret_flag))) {|bcx|
|
2012-05-22 05:20:47 -07:00
|
|
|
option::iter(copy bcx.fcx.loop_ret) {|lret|
|
2012-03-27 12:33:13 +02:00
|
|
|
Store(bcx, C_bool(true), lret.flagptr);
|
|
|
|
Store(bcx, C_bool(false), bcx.fcx.llretptr);
|
|
|
|
}
|
|
|
|
cleanup_and_leave(bcx, none, some(bcx.fcx.llreturn));
|
|
|
|
Unreachable(bcx);
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
bcx
|
2011-03-31 11:26:25 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-26 12:45:02 -07:00
|
|
|
fn invoke(bcx: block, llfn: ValueRef, llargs: [ValueRef]) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("invoke_");
|
2011-09-21 12:40:27 +02:00
|
|
|
if bcx.unreachable { ret bcx; }
|
2012-03-26 13:30:56 -07:00
|
|
|
if need_invoke(bcx) {
|
2012-03-30 17:31:40 -07:00
|
|
|
log(debug, "invoking");
|
2012-03-26 13:30:56 -07:00
|
|
|
let normal_bcx = sub_block(bcx, "normal return");
|
|
|
|
Invoke(bcx, llfn, llargs, normal_bcx.llbb, get_landing_pad(bcx));
|
|
|
|
ret normal_bcx;
|
|
|
|
} else {
|
2012-03-30 17:31:40 -07:00
|
|
|
log(debug, "calling");
|
2012-03-26 13:30:56 -07:00
|
|
|
Call(bcx, llfn, llargs);
|
|
|
|
ret bcx;
|
|
|
|
}
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2012-03-26 13:30:56 -07:00
|
|
|
fn need_invoke(bcx: block) -> bool {
|
|
|
|
if have_cached_lpad(bcx) {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Walk the scopes to look for cleanups
|
|
|
|
let mut cur = bcx;
|
|
|
|
loop {
|
|
|
|
alt cur.kind {
|
2012-04-19 16:19:53 -07:00
|
|
|
block_scope(inf) {
|
|
|
|
for inf.cleanups.each {|cleanup|
|
2012-03-26 13:30:56 -07:00
|
|
|
alt cleanup {
|
|
|
|
clean(_, cleanup_type) | clean_temp(_, _, cleanup_type) {
|
|
|
|
if cleanup_type == normal_exit_and_unwind {
|
|
|
|
ret true;
|
|
|
|
}
|
|
|
|
}
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
|
|
|
}
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
_ { }
|
|
|
|
}
|
|
|
|
cur = alt cur.parent {
|
2012-06-12 14:55:44 -07:00
|
|
|
some(next) { next }
|
|
|
|
none { ret 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-04-19 16:19:53 -07:00
|
|
|
in_lpad_scope_cx(bcx) {|inf|
|
|
|
|
alt inf.landing_pad {
|
2012-03-26 13:30:56 -07:00
|
|
|
some(_) { res = true; }
|
|
|
|
none { res = false; }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret res;
|
|
|
|
}
|
|
|
|
|
|
|
|
fn in_lpad_scope_cx(bcx: block, f: fn(scope_info)) {
|
|
|
|
let mut bcx = bcx;
|
|
|
|
loop {
|
|
|
|
alt bcx.kind {
|
2012-04-19 16:19:53 -07:00
|
|
|
block_scope(inf) {
|
2012-06-12 14:55:44 -07:00
|
|
|
if inf.cleanups.len() > 0u || is_none(bcx.parent) {
|
2012-04-19 16:19:53 -07:00
|
|
|
f(inf); ret;
|
2012-03-26 13:30:56 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
bcx = block_parent(bcx);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn get_landing_pad(bcx: block) -> BasicBlockRef {
|
|
|
|
let _icx = bcx.insn_ctxt("get_landing_pad");
|
2011-09-13 16:10:39 -07:00
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut cached = none, pad_bcx = bcx; // Guaranteed to be set below
|
2012-04-19 16:19:53 -07:00
|
|
|
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-05-22 05:20:47 -07:00
|
|
|
alt copy inf.landing_pad {
|
2012-03-26 12:39:20 +02:00
|
|
|
some(target) { cached = some(target); }
|
|
|
|
none {
|
|
|
|
pad_bcx = sub_block(bcx, "unwind");
|
2012-04-19 16:19:53 -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-02-17 11:18:14 +01:00
|
|
|
alt cached { some(b) { ret b; } none {} } // Can't return from block above
|
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.
|
|
|
|
let llretty = T_struct([T_ptr(T_i8()), T_i32()]);
|
|
|
|
// 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-02-21 14:20:18 +01: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-05-22 05:20:47 -07:00
|
|
|
alt copy bcx.fcx.personality {
|
2012-02-15 13:57:29 +01:00
|
|
|
some(addr) { Store(pad_bcx, llretval, addr); }
|
|
|
|
none {
|
|
|
|
let addr = alloca(pad_bcx, val_ty(llretval));
|
|
|
|
bcx.fcx.personality = some(addr);
|
|
|
|
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
|
|
|
|
cleanup_and_leave(pad_bcx, none, none);
|
|
|
|
ret pad_bcx.llbb;
|
2011-09-07 11:46:53 -07:00
|
|
|
}
|
|
|
|
|
2012-03-12 09:26:54 +01:00
|
|
|
fn trans_tup(bcx: block, elts: [@ast::expr], dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_tup");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2011-10-05 10:21:48 +02:00
|
|
|
let addr = alt dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(elts) {|ex| bcx = trans_expr(bcx, ex, ignore); }
|
2011-09-27 12:02:01 +02:00
|
|
|
ret bcx;
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
save_in(pos) { pos }
|
2012-02-21 14:20:18 +01:00
|
|
|
_ { bcx.tcx().sess.bug("trans_tup: weird dest"); }
|
2011-09-27 12:02:01 +02:00
|
|
|
};
|
2012-05-03 22:31:38 -07:00
|
|
|
let mut temp_cleanups = [];
|
|
|
|
for vec::eachi(elts) {|i, e|
|
|
|
|
let dst = GEPi(bcx, addr, [0u, i]);
|
2012-02-02 12:37:17 +01:00
|
|
|
let e_ty = expr_ty(bcx, e);
|
2012-03-12 09:26:54 +01:00
|
|
|
bcx = trans_expr_save_in(bcx, e, dst);
|
|
|
|
add_clean_temp_mem(bcx, dst, e_ty);
|
|
|
|
temp_cleanups += [dst];
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(temp_cleanups) {|cleanup| revoke_clean(bcx, cleanup); }
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2011-08-15 11:40:26 +02:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_rec(bcx: block, fields: [ast::field],
|
2012-01-31 17:05:20 -08:00
|
|
|
base: option<@ast::expr>, id: ast::node_id,
|
2012-02-17 13:17:40 +01:00
|
|
|
dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_rec");
|
2012-02-02 12:37:17 +01:00
|
|
|
let t = node_id_type(bcx, id);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-03-27 15:14:12 +02:00
|
|
|
let addr = alt check dest {
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(fields) {|fld|
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, fld.node.expr, ignore);
|
2011-09-27 12:02:01 +02:00
|
|
|
}
|
|
|
|
ret bcx;
|
|
|
|
}
|
2011-10-05 10:21:48 +02:00
|
|
|
save_in(pos) { pos }
|
2011-09-27 12:02:01 +02:00
|
|
|
};
|
2011-09-26 13:21:47 +02:00
|
|
|
|
2012-03-27 15:14:12 +02:00
|
|
|
let ty_fields = alt check ty::get(t).struct { ty::ty_rec(f) { f } };
|
|
|
|
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut temp_cleanups = [];
|
2012-04-06 20:01:43 +02:00
|
|
|
for fields.each {|fld|
|
2012-01-26 08:39:45 -08:00
|
|
|
let ix = option::get(vec::position(ty_fields, {|ft|
|
2012-06-10 00:49:59 -07:00
|
|
|
str::eq(*fld.node.ident, *ft.ident)
|
2011-12-16 06:27:50 -08:00
|
|
|
}));
|
2012-05-03 22:31:38 -07:00
|
|
|
let dst = GEPi(bcx, addr, [0u, ix]);
|
2012-03-12 09:26:54 +01:00
|
|
|
bcx = trans_expr_save_in(bcx, fld.node.expr, dst);
|
|
|
|
add_clean_temp_mem(bcx, dst, ty_fields[ix].mt.ty);
|
|
|
|
temp_cleanups += [dst];
|
2011-11-18 15:59:47 +01:00
|
|
|
}
|
|
|
|
alt base {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(bexp) {
|
2012-03-15 09:47:03 -04:00
|
|
|
let {bcx: cx, val: base_val} = trans_temp_expr(bcx, bexp);
|
2011-11-18 15:59:47 +01:00
|
|
|
bcx = cx;
|
|
|
|
// Copy over inherited fields
|
2012-05-03 22:31:38 -07:00
|
|
|
for ty_fields.eachi {|i, tf|
|
2012-06-10 00:49:59 -07:00
|
|
|
if !vec::any(fields, {|f| str::eq(*f.node.ident, *tf.ident)}) {
|
2012-05-03 22:31:38 -07:00
|
|
|
let dst = GEPi(bcx, addr, [0u, i]);
|
|
|
|
let base = GEPi(bcx, base_val, [0u, i]);
|
2012-03-12 09:26:54 +01:00
|
|
|
let val = load_if_immediate(bcx, base, tf.mt.ty);
|
|
|
|
bcx = copy_val(bcx, INIT, dst, val, tf.mt.ty);
|
2011-11-18 15:59:47 +01:00
|
|
|
}
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
none {}
|
2011-09-26 13:21:47 +02:00
|
|
|
};
|
2011-09-19 14:20:15 -07:00
|
|
|
|
2011-09-26 22:13:08 +02:00
|
|
|
// Now revoke the cleanups as we pass responsibility for the data
|
|
|
|
// structure on to the caller
|
2012-04-06 20:01:43 +02:00
|
|
|
for temp_cleanups.each {|cleanup| revoke_clean(bcx, cleanup); }
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2010-11-30 10:39:35 -08:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Store the result of an expression in the given memory location, ensuring
|
|
|
|
// that nil or bot expressions get ignore rather than save_in as destination.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_expr_save_in(bcx: block, e: @ast::expr, dest: ValueRef)
|
|
|
|
-> block {
|
2012-02-03 15:15:28 +01:00
|
|
|
let t = expr_ty(bcx, e);
|
|
|
|
let do_ignore = ty::type_is_bot(t) || ty::type_is_nil(t);
|
2012-01-29 21:33:08 -05:00
|
|
|
ret trans_expr(bcx, e, if do_ignore { ignore } else { save_in(dest) });
|
2011-10-04 16:37:56 +02:00
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Call this to compile an expression that you need as an intermediate value,
|
2011-10-07 11:20:51 +02:00
|
|
|
// and you want to know whether you're dealing with an lval or not (the kind
|
2011-11-18 10:20:51 +01:00
|
|
|
// field in the returned struct). For non-intermediates, use trans_expr or
|
2011-10-05 12:23:18 +02:00
|
|
|
// trans_expr_save_in. For intermediates where you don't care about lval-ness,
|
|
|
|
// use trans_temp_expr.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_temp_lval(bcx: block, e: @ast::expr) -> lval_result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_temp_lval");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-04-20 12:11:55 -07:00
|
|
|
if expr_is_lval(bcx, e) {
|
2011-10-05 10:21:48 +02:00
|
|
|
ret trans_lval(bcx, e);
|
|
|
|
} else {
|
2012-02-02 12:37:17 +01:00
|
|
|
let ty = expr_ty(bcx, e);
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_nil(ty) || ty::type_is_bot(ty) {
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, e, ignore);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: C_nil(), kind: temporary};
|
2012-02-03 15:15:28 +01:00
|
|
|
} else if ty::type_is_immediate(ty) {
|
2011-10-05 10:21:48 +02:00
|
|
|
let cell = empty_dest_cell();
|
2011-10-05 11:26:27 +02:00
|
|
|
bcx = trans_expr(bcx, e, by_val(cell));
|
|
|
|
add_clean_temp(bcx, *cell, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: *cell, kind: temporary};
|
2011-10-05 10:21:48 +02:00
|
|
|
} else {
|
2012-03-23 14:45:47 +01:00
|
|
|
let scratch = alloc_ty(bcx, ty);
|
2012-03-15 09:47:03 -04:00
|
|
|
let bcx = trans_expr_save_in(bcx, e, scratch);
|
2011-10-05 11:26:27 +02:00
|
|
|
add_clean_temp(bcx, scratch, ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
ret {bcx: bcx, val: scratch, kind: temporary};
|
2011-10-05 10:21:48 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Use only for intermediate values. See trans_expr and trans_expr_save_in for
|
|
|
|
// expressions that must 'end up somewhere' (or get ignored).
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_temp_expr(bcx: block, e: @ast::expr) -> result {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_temp_expr");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut {bcx, val, kind} = trans_temp_lval(bcx, e);
|
2011-10-07 11:20:51 +02:00
|
|
|
if kind == owned {
|
2012-02-02 12:37:17 +01:00
|
|
|
val = load_if_immediate(bcx, val, expr_ty(bcx, e));
|
2011-10-05 11:26:27 +02:00
|
|
|
}
|
|
|
|
ret {bcx: bcx, val: val};
|
|
|
|
}
|
|
|
|
|
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) {
|
|
|
|
|
|
|
|
#debug["add_root_cleanup(bcx=%s, scope_id=%d, root_loc=%s, ty=%s)",
|
|
|
|
bcx.to_str(), scope_id, val_str(bcx.ccx().tn, root_loc),
|
|
|
|
ty_to_str(bcx.ccx().tcx, ty)];
|
|
|
|
|
|
|
|
let bcx_scope = find_bcx_for_scope(bcx, scope_id);
|
|
|
|
add_clean_temp_mem(bcx_scope, root_loc, ty);
|
|
|
|
|
|
|
|
fn find_bcx_for_scope(bcx: block, scope_id: ast::node_id) -> block {
|
|
|
|
let mut bcx_sid = bcx;
|
|
|
|
loop {
|
|
|
|
bcx_sid = alt bcx_sid.node_info {
|
|
|
|
some({id, _}) if id == scope_id { ret bcx_sid; }
|
|
|
|
_ {
|
|
|
|
alt bcx_sid.parent {
|
2012-06-12 14:55:44 -07:00
|
|
|
none {
|
2012-05-14 20:32:29 -07:00
|
|
|
bcx.tcx().sess.bug(
|
|
|
|
#fmt["no enclosing scope with id %d", scope_id]);
|
|
|
|
}
|
2012-06-12 14:55:44 -07:00
|
|
|
some(bcx_par) { bcx_par }
|
2012-05-14 20:32:29 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-10-05 12:23:18 +02:00
|
|
|
// Translate an expression, with the dest argument deciding what happens with
|
|
|
|
// the result. Invariants:
|
|
|
|
// - exprs returning nil or bot always get dest=ignore
|
|
|
|
// - exprs with non-immediate type never get dest=by_val
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_expr(bcx: block, e: @ast::expr, dest: dest) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_expr");
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, e.span);
|
2011-11-15 21:11:22 -05:00
|
|
|
|
2011-12-14 15:23:11 +01:00
|
|
|
if expr_is_lval(bcx, e) {
|
2011-12-14 14:38:25 +01:00
|
|
|
ret lval_to_dps(bcx, e, dest);
|
|
|
|
}
|
2011-09-29 11:18:40 +02:00
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
ret alt bcx.ccx().maps.root_map.find({id:e.id, derefs:0u}) {
|
|
|
|
none { unrooted(bcx, e, dest) }
|
|
|
|
some(scope_id) {
|
|
|
|
#debug["expression %d found in root map with scope %d",
|
|
|
|
e.id, scope_id];
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
let ty = expr_ty(bcx, e);
|
2012-05-28 20:52:11 -07:00
|
|
|
let root_loc = alloca_zeroed(bcx, type_of(bcx.ccx(), ty));
|
2012-05-14 20:32:29 -07:00
|
|
|
let bcx = unrooted(bcx, e, save_in(root_loc));
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if !bcx.sess().no_asm_comments() {
|
2012-05-14 20:32:29 -07:00
|
|
|
add_comment(bcx, #fmt["preserving until end of scope %d",
|
|
|
|
scope_id]);
|
|
|
|
}
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-06-08 05:46:29 -07:00
|
|
|
let _icx = bcx.insn_ctxt("root_value_expr");
|
2012-05-14 20:32:29 -07:00
|
|
|
add_root_cleanup(bcx, scope_id, root_loc, ty);
|
|
|
|
let lv = {bcx: bcx, val: root_loc, kind: owned};
|
|
|
|
lval_result_to_dps(lv, ty, false, dest)
|
|
|
|
}
|
|
|
|
};
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
fn unrooted(bcx: block, e: @ast::expr, dest: dest) -> block {
|
|
|
|
let tcx = bcx.tcx();
|
|
|
|
alt e.node {
|
|
|
|
ast::expr_if(cond, thn, els) | ast::expr_if_check(cond, thn, els) {
|
|
|
|
ret trans_if(bcx, cond, thn, els, dest);
|
|
|
|
}
|
|
|
|
ast::expr_alt(expr, arms, mode) {
|
|
|
|
ret alt::trans_alt(bcx, e, expr, arms, mode, dest);
|
|
|
|
}
|
|
|
|
ast::expr_block(blk) {
|
|
|
|
ret with_scope(bcx, blk.info(), "block-expr body") {|bcx|
|
|
|
|
trans_block(bcx, blk, dest)
|
|
|
|
};
|
|
|
|
}
|
|
|
|
ast::expr_rec(args, base) {
|
|
|
|
ret trans_rec(bcx, args, base, e.id, dest);
|
|
|
|
}
|
|
|
|
ast::expr_tup(args) { ret trans_tup(bcx, args, dest); }
|
|
|
|
ast::expr_vstore(e, v) { ret tvec::trans_vstore(bcx, e, v, dest); }
|
|
|
|
ast::expr_lit(lit) { ret trans_lit(bcx, *lit, dest); }
|
|
|
|
ast::expr_vec(args, _) {
|
|
|
|
ret tvec::trans_evec(bcx, args, ast::vstore_uniq, e.id, dest);
|
|
|
|
}
|
|
|
|
ast::expr_binary(op, lhs, rhs) {
|
|
|
|
ret trans_binary(bcx, op, lhs, rhs, dest, e);
|
|
|
|
}
|
|
|
|
ast::expr_unary(op, x) {
|
|
|
|
assert op != ast::deref; // lvals are handled above
|
|
|
|
ret trans_unary(bcx, op, x, e, dest);
|
|
|
|
}
|
|
|
|
ast::expr_addr_of(_, x) { ret trans_addr_of(bcx, x, dest); }
|
|
|
|
ast::expr_fn(proto, decl, body, cap_clause) {
|
2012-06-01 19:47:04 -07:00
|
|
|
ret closure::trans_expr_fn(bcx, proto, decl, body, e.id,
|
2012-05-14 20:32:29 -07:00
|
|
|
cap_clause, none, dest);
|
|
|
|
}
|
|
|
|
ast::expr_fn_block(decl, body, cap_clause) {
|
|
|
|
alt check ty::get(expr_ty(bcx, e)).struct {
|
|
|
|
ty::ty_fn({proto, _}) {
|
|
|
|
#debug("translating fn_block %s with type %s",
|
|
|
|
expr_to_str(e), ty_to_str(tcx, expr_ty(bcx, e)));
|
2012-06-01 19:47:04 -07:00
|
|
|
ret closure::trans_expr_fn(bcx, proto, decl, body,
|
2012-05-14 20:32:29 -07:00
|
|
|
e.id, cap_clause, none, dest);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::expr_loop_body(blk) {
|
|
|
|
ret trans_loop_body(bcx, e, none, dest);
|
|
|
|
}
|
|
|
|
ast::expr_bind(f, args) {
|
|
|
|
ret closure::trans_bind(
|
|
|
|
bcx, f, args, e.id, dest);
|
|
|
|
}
|
|
|
|
ast::expr_copy(a) {
|
|
|
|
if !expr_is_lval(bcx, a) {
|
|
|
|
ret trans_expr(bcx, a, dest);
|
|
|
|
}
|
|
|
|
else { ret lval_to_dps(bcx, a, dest); }
|
|
|
|
}
|
|
|
|
ast::expr_cast(val, _) { ret trans_cast(bcx, val, e.id, dest); }
|
|
|
|
ast::expr_call(f, args, _) {
|
|
|
|
ret trans_call(bcx, e, f, arg_exprs(args), e.id, dest);
|
|
|
|
}
|
|
|
|
ast::expr_field(base, _, _) {
|
|
|
|
if dest == ignore { ret trans_expr(bcx, base, ignore); }
|
|
|
|
let callee = trans_callee(bcx, e), ty = expr_ty(bcx, e);
|
|
|
|
let lv = lval_maybe_callee_to_lval(callee, ty);
|
|
|
|
revoke_clean(lv.bcx, lv.val);
|
|
|
|
memmove_ty(lv.bcx, get_dest_addr(dest), lv.val, ty);
|
|
|
|
ret lv.bcx;
|
|
|
|
}
|
|
|
|
ast::expr_index(base, idx) {
|
|
|
|
// If it is here, it's not an lval, so this is a user-defined
|
|
|
|
// index op
|
|
|
|
let origin = bcx.ccx().maps.method_map.get(e.id);
|
|
|
|
let callee_id = ast_util::op_expr_callee_id(e);
|
|
|
|
let fty = node_id_type(bcx, callee_id);
|
|
|
|
ret trans_call_inner(
|
|
|
|
bcx, e.info(), fty,
|
|
|
|
expr_ty(bcx, e),
|
|
|
|
{ |bcx|
|
|
|
|
impl::trans_method_callee(bcx, callee_id, base, origin)
|
|
|
|
},
|
|
|
|
arg_exprs([idx]), dest);
|
|
|
|
}
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
// These return nothing
|
|
|
|
ast::expr_break {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_break(bcx);
|
|
|
|
}
|
|
|
|
ast::expr_cont {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_cont(bcx);
|
|
|
|
}
|
|
|
|
ast::expr_ret(ex) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_ret(bcx, ex);
|
|
|
|
}
|
|
|
|
ast::expr_fail(expr) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_fail_expr(bcx, some(e.span), expr);
|
|
|
|
}
|
|
|
|
ast::expr_log(_, lvl, a) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_log(e, lvl, bcx, a);
|
|
|
|
}
|
|
|
|
ast::expr_assert(a) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_check_expr(bcx, e, a, "Assertion");
|
|
|
|
}
|
|
|
|
ast::expr_check(ast::checked_expr, a) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_check_expr(bcx, e, a, "Predicate");
|
|
|
|
}
|
|
|
|
ast::expr_check(ast::claimed_expr, a) {
|
|
|
|
assert dest == ignore;
|
|
|
|
/* Claims are turned on and off by a global variable
|
|
|
|
that the RTS sets. This case generates code to
|
|
|
|
check the value of that variable, doing nothing
|
|
|
|
if it's set to false and acting like a check
|
|
|
|
otherwise. */
|
|
|
|
let c = get_extern_const(bcx.ccx().externs, bcx.ccx().llmod,
|
|
|
|
"check_claims", T_bool());
|
|
|
|
ret with_cond(bcx, Load(bcx, c)) {|bcx|
|
|
|
|
trans_check_expr(bcx, e, a, "Claim")
|
|
|
|
};
|
|
|
|
}
|
|
|
|
ast::expr_while(cond, body) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_while(bcx, cond, body);
|
|
|
|
}
|
|
|
|
ast::expr_loop(body) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_loop(bcx, body);
|
|
|
|
}
|
|
|
|
ast::expr_assign(dst, src) {
|
|
|
|
assert dest == ignore;
|
|
|
|
let src_r = trans_temp_lval(bcx, src);
|
|
|
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
|
|
|
assert kind == owned;
|
2012-05-25 00:14:40 -07:00
|
|
|
let is_last_use =
|
|
|
|
bcx.ccx().maps.last_use_map.contains_key(src.id);
|
2012-05-14 20:32:29 -07:00
|
|
|
ret store_temp_expr(bcx, DROP_EXISTING, addr, src_r,
|
|
|
|
expr_ty(bcx, src), is_last_use);
|
|
|
|
}
|
|
|
|
ast::expr_move(dst, src) {
|
2012-06-07 14:37:36 -07:00
|
|
|
// FIXME: calculate copy init-ness in typestate. (#839)
|
2012-05-14 20:32:29 -07:00
|
|
|
assert dest == ignore;
|
|
|
|
let src_r = trans_temp_lval(bcx, src);
|
|
|
|
let {bcx, val: addr, kind} = trans_lval(src_r.bcx, dst);
|
|
|
|
assert kind == owned;
|
|
|
|
ret move_val(bcx, DROP_EXISTING, addr, src_r,
|
|
|
|
expr_ty(bcx, src));
|
|
|
|
}
|
|
|
|
ast::expr_swap(dst, src) {
|
|
|
|
assert dest == ignore;
|
|
|
|
let lhs_res = trans_lval(bcx, dst);
|
|
|
|
assert lhs_res.kind == owned;
|
|
|
|
let rhs_res = trans_lval(lhs_res.bcx, src);
|
|
|
|
let t = expr_ty(bcx, src);
|
|
|
|
let tmp_alloc = alloc_ty(rhs_res.bcx, t);
|
|
|
|
// Swap through a temporary.
|
|
|
|
let bcx = move_val(rhs_res.bcx, INIT, tmp_alloc, lhs_res, t);
|
|
|
|
let bcx = move_val(bcx, INIT, lhs_res.val, rhs_res, t);
|
|
|
|
ret move_val(bcx, INIT, rhs_res.val,
|
|
|
|
lval_owned(bcx, tmp_alloc), t);
|
|
|
|
}
|
|
|
|
ast::expr_assign_op(op, dst, src) {
|
|
|
|
assert dest == ignore;
|
|
|
|
ret trans_assign_op(bcx, e, op, dst, src);
|
|
|
|
}
|
|
|
|
ast::expr_new(pool, alloc_id, val) {
|
|
|
|
// First, call pool->alloc(sz, align) to get back a void*. Then,
|
|
|
|
// cast this memory to the required type and evaluate value into
|
|
|
|
// it.
|
|
|
|
let ccx = bcx.ccx();
|
|
|
|
|
|
|
|
// Allocate space for the ptr that will be returned from
|
|
|
|
// `pool.alloc()`:
|
|
|
|
let ptr_ty = expr_ty(bcx, e);
|
|
|
|
let ptr_ptr_val = alloc_ty(bcx, ptr_ty);
|
|
|
|
|
|
|
|
#debug["ptr_ty = %s", ty_to_str(tcx, ptr_ty)];
|
|
|
|
#debug["ptr_ptr_val = %s", val_str(ccx.tn, ptr_ptr_val)];
|
|
|
|
|
|
|
|
let void_ty = ty::mk_ptr(tcx, {ty: ty::mk_nil(tcx),
|
|
|
|
mutbl: ast::m_imm});
|
|
|
|
let voidval = {
|
|
|
|
let llvoid_ty = type_of(ccx, void_ty);
|
|
|
|
PointerCast(bcx, ptr_ptr_val, T_ptr(llvoid_ty))
|
|
|
|
};
|
2012-03-14 15:16:46 -04:00
|
|
|
|
2012-05-14 20:32:29 -07:00
|
|
|
#debug["voidval = %s", val_str(ccx.tn, voidval)];
|
|
|
|
|
|
|
|
let llval_ty = type_of(ccx, expr_ty(bcx, val));
|
|
|
|
let args = [llsize_of(ccx, llval_ty), llalign_of(ccx, llval_ty)];
|
|
|
|
let origin = bcx.ccx().maps.method_map.get(alloc_id);
|
|
|
|
let bcx = trans_call_inner(
|
|
|
|
bcx, e.info(), node_id_type(bcx, alloc_id), void_ty,
|
|
|
|
{|bcx| impl::trans_method_callee(bcx, alloc_id,
|
|
|
|
pool, origin) },
|
|
|
|
arg_vals(args),
|
|
|
|
save_in(voidval));
|
|
|
|
|
|
|
|
#debug["dest = %s", dest_str(ccx, dest)];
|
|
|
|
let ptr_val = Load(bcx, ptr_ptr_val);
|
|
|
|
#debug["ptr_val = %s", val_str(ccx.tn, ptr_val)];
|
|
|
|
let bcx = trans_expr(bcx, val, save_in(ptr_val));
|
|
|
|
store_in_dest(bcx, ptr_val, dest)
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
bcx.tcx().sess.span_bug(e.span, "trans_expr reached \
|
|
|
|
fall-through case");
|
|
|
|
}
|
|
|
|
}
|
2011-09-27 13:19:55 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn lval_to_dps(bcx: block, e: @ast::expr, dest: dest) -> block {
|
2012-05-25 00:14:40 -07:00
|
|
|
let last_use_map = bcx.ccx().maps.last_use_map;
|
2012-02-02 12:37:17 +01:00
|
|
|
let ty = expr_ty(bcx, e);
|
2012-05-14 20:32:29 -07:00
|
|
|
let lv = trans_lval(bcx, e);
|
2012-05-25 00:14:40 -07:00
|
|
|
let last_use = (lv.kind == owned && last_use_map.contains_key(e.id));
|
2012-06-06 14:19:52 -07:00
|
|
|
#debug["is last use (%s) = %b, %d", expr_to_str(e), last_use,
|
|
|
|
lv.kind as int];
|
2012-05-14 20:32:29 -07:00
|
|
|
lval_result_to_dps(lv, ty, last_use, dest)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn lval_result_to_dps(lv: lval_result, ty: ty::t,
|
|
|
|
last_use: bool, dest: dest) -> block {
|
|
|
|
let mut {bcx, val, kind} = lv;
|
|
|
|
let ccx = bcx.ccx();
|
2011-09-27 13:19:55 +02:00
|
|
|
alt dest {
|
|
|
|
by_val(cell) {
|
2011-10-10 10:58:53 +02:00
|
|
|
if kind == temporary {
|
2011-09-27 13:19:55 +02:00
|
|
|
revoke_clean(bcx, val);
|
2011-09-23 21:13:50 +02:00
|
|
|
*cell = val;
|
2011-11-18 15:10:14 +01:00
|
|
|
} else if last_use {
|
|
|
|
*cell = Load(bcx, val);
|
|
|
|
if ty::type_needs_drop(ccx.tcx, ty) {
|
2012-05-28 20:52:11 -07:00
|
|
|
bcx = zero_mem(bcx, val, ty);
|
2011-11-18 15:10:14 +01:00
|
|
|
}
|
|
|
|
} else {
|
2011-10-10 13:32:50 +02:00
|
|
|
if kind == owned { val = Load(bcx, val); }
|
2011-10-10 10:58:53 +02:00
|
|
|
let {bcx: cx, val} = take_ty_immediate(bcx, val, ty);
|
|
|
|
*cell = val;
|
|
|
|
bcx = cx;
|
2011-09-23 21:13:50 +02:00
|
|
|
}
|
|
|
|
}
|
2011-11-18 15:10:14 +01:00
|
|
|
save_in(loc) {
|
|
|
|
bcx = store_temp_expr(bcx, INIT, loc, lv, ty, last_use);
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ignore {}
|
2011-05-31 14:24:04 +02:00
|
|
|
}
|
2011-09-27 13:19:55 +02:00
|
|
|
ret bcx;
|
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-03-23 14:45:47 +01:00
|
|
|
ret 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-03-23 14:45:47 +01:00
|
|
|
ret 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);
|
2011-04-12 12:06:20 -07:00
|
|
|
ret llptr;
|
|
|
|
}
|
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-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("spill_if_immediate");
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_immediate(t) { ret do_spill(cx, v, t); }
|
2012-03-23 14:45:47 +01:00
|
|
|
ret 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-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("load_if_immediate");
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_immediate(t) { ret Load(cx, v); }
|
2011-04-12 12:06:20 -07:00
|
|
|
ret v;
|
2010-12-03 13:03:07 -08:00
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn trans_log(log_ex: @ast::expr, lvl: @ast::expr,
|
|
|
|
bcx: block, e: @ast::expr) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_log");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-02-17 13:17:40 +01:00
|
|
|
if ty::type_is_bot(expr_ty(bcx, lvl)) {
|
|
|
|
ret trans_expr(bcx, lvl, ignore);
|
2012-01-19 14:28:58 -08:00
|
|
|
}
|
|
|
|
|
2012-02-03 22:11:45 +01:00
|
|
|
let modpath = [path_mod(ccx.link_meta.name)] +
|
2012-02-17 13:17:40 +01:00
|
|
|
vec::filter(bcx.fcx.path, {|e|
|
2012-02-03 22:11:45 +01:00
|
|
|
alt e { path_mod(_) { true } _ { false } }
|
|
|
|
});
|
2012-02-03 09:53:37 +01:00
|
|
|
let modname = path_str(modpath);
|
|
|
|
|
|
|
|
let global = if ccx.module_data.contains_key(modname) {
|
|
|
|
ccx.module_data.get(modname)
|
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
|
|
|
} else {
|
2011-09-26 13:21:47 +02:00
|
|
|
let s = link::mangle_internal_name_by_path_and_seq(
|
2012-06-10 00:49:59 -07:00
|
|
|
ccx, modpath, @"loglevel");
|
2012-03-14 15:10:34 -07:00
|
|
|
let global = str::as_c_str(s, {|buf|
|
2012-02-03 09:53:37 +01:00
|
|
|
llvm::LLVMAddGlobal(ccx.llmod, T_i32(), buf)
|
2011-09-26 13:21:47 +02:00
|
|
|
});
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetGlobalConstant(global, False);
|
2011-12-21 14:31:31 -08:00
|
|
|
llvm::LLVMSetInitializer(global, C_null(T_i32()));
|
2012-02-01 11:04:56 +01:00
|
|
|
lib::llvm::SetLinkage(global, lib::llvm::InternalLinkage);
|
2012-02-03 09:53:37 +01:00
|
|
|
ccx.module_data.insert(modname, global);
|
2011-09-26 13:21:47 +02:00
|
|
|
global
|
|
|
|
};
|
2012-02-17 13:17:40 +01:00
|
|
|
let current_level = Load(bcx, global);
|
2012-05-14 14:24:16 -07:00
|
|
|
let {bcx, val: level} = {
|
|
|
|
with_scope_result(bcx, lvl.info(), "level") {|bcx|
|
|
|
|
trans_temp_expr(bcx, lvl)
|
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
with_cond(bcx, ICmp(bcx, lib::llvm::IntUGE, current_level, level)) {|bcx|
|
2012-05-14 14:24:16 -07:00
|
|
|
with_scope(bcx, log_ex.info(), "log") {|bcx|
|
2012-02-17 13:17:40 +01:00
|
|
|
let {bcx, val, _} = trans_temp_expr(bcx, e);
|
|
|
|
let e_ty = expr_ty(bcx, e);
|
2012-03-21 15:42:20 +01:00
|
|
|
let tydesc = get_tydesc_simple(ccx, e_ty);
|
2012-02-17 13:17:40 +01:00
|
|
|
// Call the polymorphic log function.
|
2012-03-23 14:45:47 +01:00
|
|
|
let val = spill_if_immediate(bcx, val, e_ty);
|
2012-02-17 13:17:40 +01:00
|
|
|
let val = PointerCast(bcx, val, T_ptr(T_i8()));
|
|
|
|
Call(bcx, ccx.upcalls.log_type, [tydesc, val, level]);
|
|
|
|
bcx
|
|
|
|
}
|
|
|
|
}
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn trans_check_expr(bcx: block, chk_expr: @ast::expr,
|
|
|
|
pred_expr: @ast::expr, s: str) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_check_expr");
|
2012-05-14 14:24:16 -07:00
|
|
|
let expr_str = s + " " + expr_to_str(pred_expr) + " failed";
|
|
|
|
let {bcx, val} = {
|
|
|
|
with_scope_result(bcx, chk_expr.info(), "check") {|bcx|
|
|
|
|
trans_temp_expr(bcx, pred_expr)
|
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
};
|
|
|
|
with_cond(bcx, Not(bcx, val)) {|bcx|
|
2012-05-14 14:24:16 -07:00
|
|
|
trans_fail(bcx, some(pred_expr.span), expr_str)
|
2012-02-17 13:17:40 +01:00
|
|
|
}
|
2010-10-22 15:37:42 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_fail_expr(bcx: block, sp_opt: option<span>,
|
|
|
|
fail_expr: option<@ast::expr>) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_fail_expr");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt fail_expr {
|
|
|
|
some(expr) {
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx(), tcx = ccx.tcx;
|
2011-10-05 11:26:27 +02:00
|
|
|
let expr_res = trans_temp_expr(bcx, expr);
|
2012-02-02 12:37:17 +01:00
|
|
|
let e_ty = expr_ty(bcx, expr);
|
2011-07-27 14:19:39 +02:00
|
|
|
bcx = expr_res.bcx;
|
2011-07-01 14:33:15 -04:00
|
|
|
|
2012-02-03 15:15:28 +01:00
|
|
|
if ty::type_is_str(e_ty) {
|
2012-06-12 16:41:20 -07:00
|
|
|
let body = tvec::get_bodyptr(bcx, expr_res.val);
|
|
|
|
let data = tvec::get_dataptr(bcx, body);
|
2011-09-02 16:09:41 +02:00
|
|
|
ret trans_fail_value(bcx, sp_opt, data);
|
2012-02-03 15:15:28 +01:00
|
|
|
} else if bcx.unreachable || ty::type_is_bot(e_ty) {
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
2012-02-21 14:20:18 +01:00
|
|
|
bcx.sess().span_bug(
|
2011-09-26 13:21:47 +02:00
|
|
|
expr.span, "fail called with unsupported type " +
|
|
|
|
ty_to_str(tcx, e_ty));
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2011-09-02 15:34:58 -07:00
|
|
|
_ { ret trans_fail(bcx, sp_opt, "explicit failure"); }
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
|
|
|
}
|
2011-07-13 15:44:09 -07:00
|
|
|
|
2012-05-18 19:02:39 -07:00
|
|
|
fn trans_trace(bcx: block, sp_opt: option<span>, trace_str: str) {
|
|
|
|
if !bcx.sess().trace() { ret; }
|
|
|
|
let _icx = bcx.insn_ctxt("trans_trace");
|
|
|
|
add_comment(bcx, trace_str);
|
|
|
|
let V_trace_str = C_cstr(bcx.ccx(), trace_str);
|
|
|
|
let {V_filename, V_line} = alt sp_opt {
|
|
|
|
some(sp) {
|
|
|
|
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}
|
|
|
|
}
|
|
|
|
none {
|
|
|
|
{V_filename: C_cstr(bcx.ccx(), "<runtime>"),
|
|
|
|
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()));
|
|
|
|
let args = [V_trace_str, V_filename, C_int(ccx, V_line)];
|
|
|
|
Call(bcx, ccx.upcalls.trace, args);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_fail(bcx: block, sp_opt: option<span>, fail_str: str) ->
|
|
|
|
block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_fail");
|
2012-02-21 14:20:18 +01:00
|
|
|
let V_fail_str = C_cstr(bcx.ccx(), fail_str);
|
2011-09-26 13:21:47 +02:00
|
|
|
ret trans_fail_value(bcx, sp_opt, V_fail_str);
|
2011-07-01 14:33:15 -04:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_fail_value(bcx: block, sp_opt: option<span>,
|
|
|
|
V_fail_str: ValueRef) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_fail_value");
|
2012-02-21 14:20:18 +01:00
|
|
|
let ccx = bcx.ccx();
|
2012-03-15 09:47:03 -04:00
|
|
|
let {V_filename, V_line} = alt sp_opt {
|
2011-07-27 14:19:39 +02:00
|
|
|
some(sp) {
|
2012-02-21 14:20:18 +01:00
|
|
|
let sess = bcx.sess();
|
2012-01-12 17:59:49 +01:00
|
|
|
let loc = codemap::lookup_char_pos(sess.parse_sess.cm, sp.lo);
|
2012-03-15 09:47:03 -04:00
|
|
|
{V_filename: C_cstr(bcx.ccx(), loc.file.name),
|
|
|
|
V_line: loc.line as int}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-03-15 09:47:03 -04:00
|
|
|
none {
|
|
|
|
{V_filename: C_cstr(bcx.ccx(), "<runtime>"),
|
|
|
|
V_line: 0}
|
|
|
|
}
|
|
|
|
};
|
2011-09-26 13:21:47 +02:00
|
|
|
let V_str = PointerCast(bcx, V_fail_str, T_ptr(T_i8()));
|
2012-03-15 09:47:03 -04:00
|
|
|
let V_filename = PointerCast(bcx, V_filename, T_ptr(T_i8()));
|
2011-10-25 13:13:55 -07:00
|
|
|
let args = [V_str, V_filename, C_int(ccx, V_line)];
|
2012-02-21 14:20:18 +01:00
|
|
|
let bcx = invoke(bcx, bcx.ccx().upcalls._fail, args);
|
2011-09-26 13:21:47 +02:00
|
|
|
Unreachable(bcx);
|
|
|
|
ret bcx;
|
2011-01-28 00:09:26 -05:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_break_cont(bcx: block, to_end: bool)
|
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_break_cont");
|
2011-03-25 16:28:16 +01:00
|
|
|
// Locate closest loop block, outputting cleanup as we go.
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut unwind = bcx;
|
2012-05-25 16:32:37 -07:00
|
|
|
let mut target;
|
2012-03-10 20:34:17 -08:00
|
|
|
loop {
|
2012-02-15 13:57:29 +01:00
|
|
|
alt unwind.kind {
|
2012-05-14 08:40:51 -07:00
|
|
|
block_scope({loop_break: some(brk), _}) {
|
2012-02-15 13:57:29 +01:00
|
|
|
target = if to_end {
|
2012-02-17 11:18:14 +01:00
|
|
|
brk
|
2011-07-27 14:19:39 +02:00
|
|
|
} else {
|
2012-05-14 08:40:51 -07:00
|
|
|
unwind
|
2012-02-15 13:57:29 +01:00
|
|
|
};
|
|
|
|
break;
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
_ {}
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
2012-03-26 16:09:27 +02:00
|
|
|
unwind = alt unwind.parent {
|
2012-06-12 14:55:44 -07:00
|
|
|
some(cx) { cx }
|
2012-03-26 16:09:27 +02:00
|
|
|
// This is a return from a loop body block
|
2012-06-12 14:55:44 -07:00
|
|
|
none {
|
2012-03-26 16:09:27 +02:00
|
|
|
Store(bcx, C_bool(!to_end), bcx.fcx.llretptr);
|
|
|
|
cleanup_and_leave(bcx, none, some(bcx.fcx.llreturn));
|
|
|
|
Unreachable(bcx);
|
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
};
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
cleanup_and_Br(bcx, unwind, target.llbb);
|
|
|
|
Unreachable(bcx);
|
|
|
|
ret bcx;
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_break(cx: block) -> block {
|
2012-01-27 12:55:21 +01:00
|
|
|
ret trans_break_cont(cx, true);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_cont(cx: block) -> block {
|
2012-01-27 12:55:21 +01:00
|
|
|
ret trans_break_cont(cx, false);
|
2011-03-25 16:28:16 +01:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_ret(bcx: block, e: option<@ast::expr>) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_ret");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-05-22 05:20:47 -07:00
|
|
|
let retptr = alt copy bcx.fcx.loop_ret {
|
2012-03-27 12:33:13 +02:00
|
|
|
some({flagptr, retptr}) {
|
|
|
|
// This is a loop body return. Must set continue flag (our retptr)
|
|
|
|
// to false, return flag to true, and then store the value in the
|
|
|
|
// parent's retptr.
|
|
|
|
Store(bcx, C_bool(true), flagptr);
|
|
|
|
Store(bcx, C_bool(false), bcx.fcx.llretptr);
|
|
|
|
alt e {
|
|
|
|
some(x) { PointerCast(bcx, retptr,
|
|
|
|
T_ptr(type_of(bcx.ccx(), expr_ty(bcx, x)))) }
|
|
|
|
none { retptr }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
none { bcx.fcx.llretptr }
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
alt e {
|
2012-03-27 12:33:13 +02:00
|
|
|
some(x) {
|
|
|
|
bcx = trans_expr_save_in(bcx, x, retptr);
|
|
|
|
}
|
2011-09-21 11:39:06 +02:00
|
|
|
_ {}
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
cleanup_and_leave(bcx, none, some(bcx.fcx.llreturn));
|
2011-09-21 12:40:27 +02:00
|
|
|
Unreachable(bcx);
|
2011-09-26 13:21:47 +02:00
|
|
|
ret bcx;
|
2010-10-22 19:23:10 -07:00
|
|
|
}
|
|
|
|
|
2012-03-22 13:44:20 -07:00
|
|
|
fn build_return(bcx: block) {
|
|
|
|
let _icx = bcx.insn_ctxt("build_return");
|
|
|
|
Br(bcx, bcx.fcx.llreturn);
|
|
|
|
}
|
2011-08-17 17:49:54 -07:00
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn init_local(bcx: block, local: @ast::local) -> block {
|
2012-03-22 13:44:20 -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);
|
2011-10-07 11:20:51 +02:00
|
|
|
let llptr = alt bcx.fcx.lllocals.find(local.node.id) {
|
|
|
|
some(local_mem(v)) { v }
|
2012-06-06 14:19:52 -07:00
|
|
|
_ { bcx.tcx().sess.span_bug(local.span,
|
2012-01-30 21:00:57 -08:00
|
|
|
"init_local: Someone forgot to document why it's\
|
|
|
|
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;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt local.node.init {
|
|
|
|
some(init) {
|
2011-12-14 15:23:11 +01:00
|
|
|
if init.op == ast::init_assign || !expr_is_lval(bcx, init.expr) {
|
2011-10-05 10:21:48 +02:00
|
|
|
bcx = trans_expr_save_in(bcx, init.expr, llptr);
|
2011-09-28 15:15:29 +02:00
|
|
|
} else { // This is a move from an lval, must perform an actual move
|
2011-07-27 14:19:39 +02:00
|
|
|
let sub = trans_lval(bcx, init.expr);
|
2011-09-16 16:27:34 +02:00
|
|
|
bcx = move_val(sub.bcx, INIT, llptr, sub, ty);
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-05-28 20:52:11 -07:00
|
|
|
_ { bcx = zero_mem(bcx, llptr, ty); }
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
2011-09-28 10:41:19 +02:00
|
|
|
// Make a note to drop this slot on the way out.
|
|
|
|
add_clean(bcx, llptr, ty);
|
2012-01-27 13:17:06 +01:00
|
|
|
ret 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-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_stmt");
|
2012-03-07 15:13:31 -08:00
|
|
|
#debug["trans_stmt(%s)", stmt_to_str(s)];
|
2012-02-01 18:52:08 -08:00
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if !cx.sess().no_asm_comments() {
|
2011-12-06 14:02:06 -08:00
|
|
|
add_span_comment(cx, s.span, stmt_to_str(s));
|
|
|
|
}
|
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
|
|
|
|
2011-07-27 14:19:39 +02:00
|
|
|
alt s.node {
|
2012-01-04 14:16:41 -08:00
|
|
|
ast::stmt_expr(e, _) | ast::stmt_semi(e, _) {
|
|
|
|
bcx = trans_expr(cx, e, ignore);
|
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
ast::stmt_decl(d, _) {
|
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locals) {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(locals) {|local|
|
2012-02-10 14:33:36 +01:00
|
|
|
bcx = init_local(bcx, local);
|
2012-02-21 14:20:18 +01:00
|
|
|
if cx.sess().opts.extra_debuginfo {
|
2011-12-14 15:14:06 -05:00
|
|
|
debuginfo::create_local_var(bcx, local);
|
2011-11-15 21:11:22 -05:00
|
|
|
}
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-02-03 09:53:37 +01:00
|
|
|
ast::decl_item(i) { trans_item(cx.fcx.ccx, *i); }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2010-09-23 13:15:51 -07:00
|
|
|
}
|
2011-11-15 21:11:22 -05:00
|
|
|
|
2011-09-23 21:13:38 +02:00
|
|
|
ret 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-06-12 14:55:44 -07:00
|
|
|
fn new_block(cx: fn_ctxt, parent: option<block>, +kind: block_kind,
|
2012-05-14 14:24:16 -07:00
|
|
|
name: str, opt_node_info: option<node_info>) -> block {
|
|
|
|
|
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)
|
|
|
|
} else { "" };
|
2012-03-14 15:10:34 -07:00
|
|
|
let llbb: BasicBlockRef = str::as_c_str(s, {|buf|
|
2012-02-17 11:18:14 +01:00
|
|
|
llvm::LLVMAppendBasicBlock(cx.llfn, buf)
|
|
|
|
});
|
2012-06-12 14:55:44 -07:00
|
|
|
let bcx = mk_block(llbb, parent, kind, opt_node_info, cx);
|
|
|
|
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
|
|
|
};
|
2011-09-21 12:40:27 +02:00
|
|
|
ret bcx;
|
2010-09-27 15:38:34 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn simple_block_scope() -> block_kind {
|
2012-05-14 08:40:51 -07:00
|
|
|
block_scope({loop_break: none, mut cleanups: [],
|
2012-03-26 18:35:18 -07:00
|
|
|
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-05-14 14:24:16 -07:00
|
|
|
fn top_scope_block(fcx: fn_ctxt, opt_node_info: option<node_info>) -> block {
|
2012-06-12 14:55:44 -07:00
|
|
|
ret new_block(fcx, none, simple_block_scope(),
|
2012-05-14 14:24:16 -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,
|
|
|
|
opt_node_info: option<node_info>,
|
|
|
|
n: str) -> block {
|
2012-06-12 14:55:44 -07:00
|
|
|
ret new_block(bcx.fcx, some(bcx), simple_block_scope(),
|
2012-05-14 14:24:16 -07:00
|
|
|
n, opt_node_info);
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn loop_scope_block(bcx: block, loop_break: block, n: str,
|
|
|
|
opt_node_info: option<node_info>) -> block {
|
2012-06-12 14:55:44 -07:00
|
|
|
ret new_block(bcx.fcx, some(bcx), block_scope({
|
2012-05-14 08:40:51 -07:00
|
|
|
loop_break: some(loop_break),
|
2012-03-26 18:35:18 -07:00
|
|
|
mut cleanups: [],
|
|
|
|
mut cleanup_paths: [],
|
|
|
|
mut landing_pad: none
|
2012-05-14 14:24:16 -07:00
|
|
|
}), n, opt_node_info);
|
2011-03-25 16:28:16 +01: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-02-17 13:17:40 +01:00
|
|
|
fn sub_block(bcx: block, n: str) -> block {
|
2012-06-12 14:55:44 -07:00
|
|
|
new_block(bcx.fcx, some(bcx), block_non_scope, n, none)
|
2010-10-04 15:55:12 -07:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
|
2012-02-21 15:11:20 +01:00
|
|
|
fn raw_block(fcx: fn_ctxt, llbb: BasicBlockRef) -> block {
|
2012-06-12 14:55:44 -07:00
|
|
|
mk_block(llbb, none, block_non_scope, 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-03-23 17:52:20 -07:00
|
|
|
fn trans_block_cleanups(bcx: block, cleanup_cx: block) -> block {
|
|
|
|
trans_block_cleanups_(bcx, cleanup_cx, false)
|
|
|
|
}
|
|
|
|
|
|
|
|
fn trans_block_cleanups_(bcx: block, cleanup_cx: block, is_lpad: bool) ->
|
2012-02-17 13:17:40 +01:00
|
|
|
block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_block_cleanups");
|
2011-09-21 12:40:27 +02:00
|
|
|
if bcx.unreachable { ret bcx; }
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2012-02-17 11:18:14 +01:00
|
|
|
alt check cleanup_cx.kind {
|
2012-02-17 13:17:40 +01:00
|
|
|
block_scope({cleanups, _}) {
|
2012-05-18 10:40:54 -07:00
|
|
|
let cleanups = copy cleanups;
|
|
|
|
vec::riter(cleanups) {|cu|
|
2012-03-23 17:52:20 -07:00
|
|
|
alt cu {
|
|
|
|
clean(cfn, cleanup_type) | clean_temp(_, cfn, cleanup_type) {
|
|
|
|
// 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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
Make moving of temporaries do the right thing, use it to optimize
This adds support for dropping cleanups for temporary values when they
are moved somewhere else. It then adds wraps most copy operations
(return, put in data structure, box, etc) in a way that will fall back
to a move when it is safe.
This saves a lot of taking/dropping, shaving over a megabyte off the
stage2/rustc binary size.
In some cases, most notably function returns, we could detect that the
returned value is a local variable, and can thus be safely moved even
though it is not a temporary. This will require putting some more
information in lvals.
I did not yet handle function arguments, since the logic for passing
them looked too convoluted to touch. I'll probably try that in the
near future, since it's bound to be a big win.
2011-07-07 13:36:12 +02:00
|
|
|
}
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
2010-09-29 17:22:07 -07:00
|
|
|
}
|
2010-10-04 15:55:12 -07:00
|
|
|
ret bcx;
|
|
|
|
}
|
|
|
|
|
2012-02-15 13:57:29 +01:00
|
|
|
// In the last argument, some(block) mean jump to this block, and none means
|
|
|
|
// this is a landing pad and leaving should be accomplished with a resume
|
|
|
|
// instruction.
|
2012-02-17 13:17:40 +01:00
|
|
|
fn cleanup_and_leave(bcx: block, upto: option<BasicBlockRef>,
|
2012-02-15 13:57:29 +01:00
|
|
|
leave: option<BasicBlockRef>) {
|
2012-03-22 13:44:20 -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-03-23 17:52:20 -07:00
|
|
|
let is_lpad = leave == none;
|
2012-03-10 20:34:17 -08:00
|
|
|
loop {
|
2012-05-14 20:32:29 -07:00
|
|
|
#debug["cleanup_and_leave: leaving %s", cur.to_str()];
|
|
|
|
|
2012-05-18 19:02:39 -07:00
|
|
|
if bcx.sess().trace() {
|
|
|
|
trans_trace(
|
|
|
|
bcx, none,
|
|
|
|
#fmt["cleanup_and_leave(%s)", cur.to_str()]);
|
2012-05-14 20:32:29 -07:00
|
|
|
}
|
|
|
|
|
2012-02-17 11:18:14 +01:00
|
|
|
alt cur.kind {
|
2012-04-19 16:19:53 -07:00
|
|
|
block_scope(inf) if inf.cleanups.len() > 0u {
|
2012-05-14 20:32:29 -07:00
|
|
|
for vec::find(inf.cleanup_paths,
|
|
|
|
{|cp| cp.target == leave}).each {|cp|
|
2012-04-06 20:01:43 +02:00
|
|
|
Br(bcx, cp.dest);
|
2012-05-14 20:32:29 -07:00
|
|
|
ret;
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
2012-02-17 13:17:40 +01:00
|
|
|
let sub_cx = sub_block(bcx, "cleanup");
|
2012-02-15 13:57:29 +01:00
|
|
|
Br(bcx, sub_cx.llbb);
|
2012-04-19 16:19:53 -07:00
|
|
|
inf.cleanup_paths += [{target: leave, dest: sub_cx.llbb}];
|
2012-03-23 17:52:20 -07:00
|
|
|
bcx = trans_block_cleanups_(sub_cx, cur, is_lpad);
|
2012-02-17 11:18:14 +01:00
|
|
|
}
|
|
|
|
_ {}
|
2012-02-15 13:57:29 +01:00
|
|
|
}
|
|
|
|
alt upto {
|
|
|
|
some(bb) { if cur.llbb == bb { break; } }
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
cur = alt cur.parent {
|
2012-06-12 14:55:44 -07:00
|
|
|
some(next) { next }
|
|
|
|
none { assert is_none(upto); break; }
|
2012-02-15 13:57:29 +01:00
|
|
|
};
|
|
|
|
}
|
|
|
|
alt leave {
|
|
|
|
some(target) { Br(bcx, target); }
|
|
|
|
none { Resume(bcx, Load(bcx, option::get(bcx.fcx.personality))); }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("cleanup_and_Br");
|
2012-02-15 13:57:29 +01:00
|
|
|
cleanup_and_leave(bcx, some(upto.llbb), some(target));
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn leave_block(bcx: block, out_of: block) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("leave_block");
|
2012-02-17 13:17:40 +01:00
|
|
|
let next_cx = sub_block(block_parent(out_of), "next");
|
|
|
|
if bcx.unreachable { Unreachable(next_cx); }
|
|
|
|
cleanup_and_Br(bcx, out_of, next_cx.llbb);
|
|
|
|
next_cx
|
|
|
|
}
|
|
|
|
|
2012-05-14 14:24:16 -07:00
|
|
|
fn with_scope(bcx: block, opt_node_info: option<node_info>,
|
|
|
|
name: str, f: fn(block) -> block) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("with_scope");
|
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-05-14 14:24:16 -07:00
|
|
|
fn with_scope_result(bcx: block, opt_node_info: option<node_info>,
|
|
|
|
name: str, f: fn(block) -> result)
|
2012-02-17 13:17:40 +01:00
|
|
|
-> result {
|
2012-03-22 13:44:20 -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);
|
|
|
|
let {bcx, val} = f(scope_cx);
|
|
|
|
{bcx: leave_block(bcx, scope_cx), val: val}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn with_cond(bcx: block, val: ValueRef, f: fn(block) -> block) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("with_cond");
|
2012-02-17 13:17:40 +01:00
|
|
|
let next_cx = sub_block(bcx, "next"), cond_cx = 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
|
|
|
|
}
|
|
|
|
|
2012-01-23 14:59:00 -08:00
|
|
|
fn block_locals(b: ast::blk, it: fn(@ast::local)) {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(b.node.stmts) {|s|
|
2011-07-27 14:19:39 +02:00
|
|
|
alt s.node {
|
|
|
|
ast::stmt_decl(d, _) {
|
|
|
|
alt d.node {
|
|
|
|
ast::decl_local(locals) {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(locals) {|local| it(local); }
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
_ {/* fall through */ }
|
2010-10-19 14:54:10 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-23 14:45:47 +01:00
|
|
|
fn alloc_ty(bcx: block, t: ty::t) -> ValueRef {
|
|
|
|
let _icx = bcx.insn_ctxt("alloc_ty");
|
|
|
|
let ccx = bcx.ccx();
|
2012-02-07 11:25:04 +01:00
|
|
|
let llty = type_of(ccx, t);
|
2012-05-25 15:29:27 -07:00
|
|
|
if ty::type_has_params(t) { log(error, ty_to_str(ccx.tcx, t)); }
|
2012-03-12 10:05:15 +01:00
|
|
|
assert !ty::type_has_params(t);
|
2012-03-11 12:09:38 +01:00
|
|
|
let val = alloca(bcx, llty);
|
2012-03-23 14:45:47 +01:00
|
|
|
ret val;
|
2011-01-21 07:58:16 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn alloc_local(cx: block, local: @ast::local) -> block {
|
2012-03-22 13:44:20 -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-02-22 16:57:23 +01:00
|
|
|
let simple_name = alt local.node.pat.node {
|
|
|
|
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-04-06 12:14:09 -07:00
|
|
|
option::iter(simple_name) {|name|
|
2012-06-10 00:49:59 -07:00
|
|
|
str::as_c_str(*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-03-23 14:45:47 +01:00
|
|
|
ret cx;
|
2011-02-10 15:00:16 -08:00
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trans_block(bcx: block, b: ast::blk, dest: dest)
|
|
|
|
-> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = bcx.insn_ctxt("trans_block");
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = bcx;
|
2011-10-21 13:14:28 +02:00
|
|
|
block_locals(b) {|local| bcx = alloc_local(bcx, local); };
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(b.node.stmts) {|s|
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, b.span);
|
2011-09-23 21:13:38 +02:00
|
|
|
bcx = trans_stmt(bcx, *s);
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
|
|
|
alt b.node.expr {
|
2011-09-26 13:21:47 +02:00
|
|
|
some(e) {
|
2012-02-03 15:15:28 +01:00
|
|
|
let bt = ty::type_is_bot(expr_ty(bcx, e));
|
2011-12-18 23:32:38 -05:00
|
|
|
debuginfo::update_source_pos(bcx, e.span);
|
2012-01-29 21:33:08 -05:00
|
|
|
bcx = trans_expr(bcx, e, if bt { ignore } else { dest });
|
2011-09-26 13:21:47 +02:00
|
|
|
}
|
2011-09-23 21:13:50 +02:00
|
|
|
_ { assert dest == ignore || bcx.unreachable; }
|
2010-11-29 17:11:03 -08:00
|
|
|
}
|
2012-02-15 13:57:29 +01:00
|
|
|
ret bcx;
|
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} {
|
|
|
|
{sa: str::as_c_str("static_allocas", {|buf|
|
|
|
|
llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
ca: str::as_c_str("load_env", {|buf|
|
|
|
|
llvm::LLVMAppendBasicBlock(llfn, buf) }),
|
|
|
|
rt: str::as_c_str("return", {|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-02-09 11:17:11 +01:00
|
|
|
param_substs: option<param_substs>,
|
2012-02-21 15:11:20 +01:00
|
|
|
sp: option<span>) -> fn_ctxt {
|
2011-07-27 14:19:39 +02:00
|
|
|
let llbbs = mk_standard_basic_blocks(llfndecl);
|
|
|
|
ret @{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,
|
|
|
|
mut llself: none,
|
|
|
|
mut personality: none,
|
2012-03-27 12:33:13 +02:00
|
|
|
mut loop_ret: none,
|
2012-03-14 12:07:23 -07:00
|
|
|
llargs: int_hash::<local_val>(),
|
|
|
|
lllocals: int_hash::<local_val>(),
|
|
|
|
llupvars: int_hash::<ValueRef>(),
|
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-02-21 15:11:20 +01:00
|
|
|
sp: option<span>) -> fn_ctxt {
|
2012-03-23 19:49:01 -07:00
|
|
|
ret 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-03-11 12:06:05 +01:00
|
|
|
args: [ast::arg]) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("create_llargs_for_fn_args");
|
2012-02-21 14:20:18 +01:00
|
|
|
// Skip the implicit arguments 0, and 1.
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut arg_n = first_real_arg;
|
2011-07-27 14:19:39 +02:00
|
|
|
alt ty_self {
|
2012-01-13 10:58:31 +01:00
|
|
|
impl_self(tt) {
|
2011-12-16 11:37:38 +01:00
|
|
|
cx.llself = some({v: cx.llenv, t: tt});
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
no_self {}
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2011-08-02 16:24:38 -07:00
|
|
|
|
2011-06-01 11:34:52 -07:00
|
|
|
// Populate the llargs field of the function context with the ValueRefs
|
|
|
|
// that we get from llvm::LLVMGetParam for each argument.
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(args) {|arg|
|
2012-01-18 19:29:37 +08:00
|
|
|
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
|
2011-05-02 17:47:24 -07:00
|
|
|
assert (llarg as int != 0);
|
2011-10-07 11:20:51 +02:00
|
|
|
// Note that this uses local_mem even for things passed by value.
|
|
|
|
// copy_args_to_allocas will overwrite the table entry with local_imm
|
|
|
|
// before it's actually used.
|
|
|
|
cx.llargs.insert(arg.id, local_mem(llarg));
|
2012-01-18 19:29:37 +08:00
|
|
|
arg_n += 1u;
|
2010-12-09 17:38:17 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-21 15:11:20 +01:00
|
|
|
fn copy_args_to_allocas(fcx: fn_ctxt, bcx: block, args: [ast::arg],
|
2012-02-17 13:17:40 +01:00
|
|
|
arg_tys: [ty::arg]) -> block {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = fcx.insn_ctxt("copy_args_to_allocas");
|
2012-02-21 14:20:18 +01:00
|
|
|
let tcx = bcx.tcx();
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut arg_n: uint = 0u, bcx = bcx;
|
2012-02-02 16:50:17 -08:00
|
|
|
let epic_fail = fn@() -> ! {
|
2012-03-05 16:27:27 -08:00
|
|
|
tcx.sess.bug("someone forgot\
|
2012-01-30 21:00:57 -08:00
|
|
|
to document an invariant in copy_args_to_allocas!");
|
2012-02-05 09:56:10 -08:00
|
|
|
};
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(arg_tys) {|arg|
|
2011-10-06 14:17:56 +02:00
|
|
|
let id = args[arg_n].id;
|
2012-01-30 21:00:57 -08:00
|
|
|
let argval = alt fcx.llargs.get(id) { local_mem(v) { v }
|
|
|
|
_ { epic_fail() } };
|
2012-02-02 16:50:17 -08:00
|
|
|
alt ty::resolved_mode(tcx, arg.mode) {
|
2012-02-15 11:25:39 -08:00
|
|
|
ast::by_mutbl_ref { }
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::by_move | ast::by_copy { add_clean(bcx, argval, arg.ty); }
|
|
|
|
ast::by_val {
|
2012-02-03 15:15:28 +01:00
|
|
|
if !ty::type_is_immediate(arg.ty) {
|
2012-03-23 14:45:47 +01:00
|
|
|
let alloc = alloc_ty(bcx, arg.ty);
|
2011-10-07 11:20:51 +02:00
|
|
|
Store(bcx, argval, alloc);
|
|
|
|
fcx.llargs.insert(id, local_mem(alloc));
|
|
|
|
} else {
|
|
|
|
fcx.llargs.insert(id, local_imm(argval));
|
2011-10-06 14:17:56 +02:00
|
|
|
}
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::by_ref {}
|
2010-12-07 12:34:10 -08:00
|
|
|
}
|
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
|
|
|
arg_n += 1u;
|
|
|
|
}
|
2011-09-23 11:01:09 +02:00
|
|
|
ret 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-03-22 13:44:20 -07:00
|
|
|
let _icx = fcx.insn_ctxt("finish_fn");
|
2012-02-13 16:06:56 -08:00
|
|
|
tie_up_header_blocks(fcx, lltop);
|
2012-02-17 13:17:40 +01:00
|
|
|
let ret_cx = raw_block(fcx, 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-03-22 13:44:20 -07:00
|
|
|
let _icx = fcx.insn_ctxt("tie_up_header_blocks");
|
2012-02-17 13:17:40 +01:00
|
|
|
Br(raw_block(fcx, fcx.llstaticallocas), fcx.llloadenv);
|
2012-03-12 10:05:15 +01:00
|
|
|
Br(raw_block(fcx, fcx.llloadenv), lltop);
|
2011-05-11 11:56:49 -07:00
|
|
|
}
|
|
|
|
|
2012-01-19 17:56:05 -08:00
|
|
|
enum self_arg { impl_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-02-09 11:17:11 +01: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-03-22 13:44:20 -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,
|
|
|
|
some(body.span));
|
2012-03-11 12:06:05 +01:00
|
|
|
create_llargs_for_fn_args(fcx, ty_self, decl.inputs);
|
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));
|
2011-12-22 17:49:54 +01:00
|
|
|
bcx = copy_args_to_allocas(fcx, bcx, decl.inputs, 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-03-03 17:49:23 -08:00
|
|
|
|
2012-03-23 19:49:01 -07:00
|
|
|
if !ccx.class_ctors.contains_key(id) // hack --
|
2012-03-03 17:49:23 -08:00
|
|
|
/* avoids the need for special cases to assign a type to
|
|
|
|
the constructor body (since it has no explicit return) */
|
|
|
|
&&
|
|
|
|
(option::is_none(body.node.expr) ||
|
2012-02-03 15:15:28 +01:00
|
|
|
ty::type_is_bot(block_ty) ||
|
2012-03-03 17:49:23 -08:00
|
|
|
ty::type_is_nil(block_ty)) {
|
2012-02-15 13:57:29 +01:00
|
|
|
bcx = trans_block(bcx, body, ignore);
|
2011-09-27 08:42:27 +02:00
|
|
|
} else {
|
2012-02-15 13:57:29 +01:00
|
|
|
bcx = trans_block(bcx, body, save_in(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,
|
|
|
|
param_substs: option<param_substs>,
|
2012-03-23 19:49:01 -07:00
|
|
|
id: ast::node_id) {
|
2012-05-17 21:53:49 -07:00
|
|
|
let do_time = ccx.sess.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-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_fn");
|
2012-02-02 12:37:17 +01:00
|
|
|
trans_closure(ccx, path, decl, body, llfndecl, ty_self,
|
2012-03-23 19:49:01 -07:00
|
|
|
param_substs, id, {|fcx|
|
2012-02-02 12:37:17 +01:00
|
|
|
if ccx.sess.opts.extra_debuginfo {
|
|
|
|
debuginfo::create_function(fcx);
|
|
|
|
}
|
2012-03-26 16:09:27 +02:00
|
|
|
}, {|_bcx|});
|
2011-10-05 11:51:41 +02:00
|
|
|
if do_time {
|
|
|
|
let end = time::get_time();
|
2012-02-03 09:53:37 +01:00
|
|
|
log_fn_time(ccx, path_str(path), start, end);
|
2011-07-19 11:56:46 -07:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_res_ctor(ccx: @crate_ctxt, path: path, dtor: ast::fn_decl,
|
2012-03-08 13:30:22 +01:00
|
|
|
ctor_id: ast::node_id,
|
2012-02-09 11:17:11 +01:00
|
|
|
param_substs: option<param_substs>, llfndecl: ValueRef) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_res_ctor");
|
2011-06-30 12:35:19 +02:00
|
|
|
// Create a function for the constructor
|
2012-03-23 19:49:01 -07:00
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, path, llfndecl, ctor_id, param_substs,
|
|
|
|
none);
|
2012-03-11 12:06:05 +01:00
|
|
|
create_llargs_for_fn_args(fcx, no_self, dtor.inputs);
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut bcx = top_scope_block(fcx, none), lltop = bcx.llbb;
|
2012-02-08 10:05:44 +01:00
|
|
|
let fty = node_id_type(bcx, ctor_id);
|
|
|
|
let arg_t = ty::ty_fn_args(fty)[0].ty;
|
2011-12-22 17:49:54 +01:00
|
|
|
let arg = alt fcx.llargs.find(dtor.inputs[0].id) {
|
2011-11-16 13:35:34 +01:00
|
|
|
some(local_mem(x)) { x }
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { ccx.sess.bug("Someone forgot to document an invariant \
|
|
|
|
in trans_res_ctor"); }
|
2011-11-16 13:35:34 +01:00
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
let llretptr = fcx.llretptr;
|
2011-06-30 14:46:17 +02:00
|
|
|
|
2012-05-03 22:31:38 -07:00
|
|
|
let dst = GEPi(bcx, llretptr, [0u, 1u]);
|
2012-03-23 14:45:47 +01:00
|
|
|
memmove_ty(bcx, dst, arg, arg_t);
|
2012-05-03 22:31:38 -07:00
|
|
|
let flag = GEPi(bcx, llretptr, [0u, 0u]);
|
2012-02-21 14:51:17 +01:00
|
|
|
let one = C_u8(1u);
|
2012-03-12 09:26:54 +01:00
|
|
|
Store(bcx, one, flag);
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-06-24 18:10:40 +02:00
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_enum_variant(ccx: @crate_ctxt, enum_id: ast::node_id,
|
2012-02-03 09:53:37 +01:00
|
|
|
variant: ast::variant, disr: int, is_degen: bool,
|
2012-02-09 11:17:11 +01:00
|
|
|
param_substs: option<param_substs>,
|
|
|
|
llfndecl: ValueRef) {
|
2012-03-22 13:44:20 -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-03-27 15:14:12 +02:00
|
|
|
let fn_args = vec::map(variant.node.args, {|varg|
|
|
|
|
{mode: ast::expl(ast::by_copy),
|
|
|
|
ty: varg.ty,
|
2012-06-10 00:49:59 -07:00
|
|
|
ident: @"arg",
|
2012-03-27 15:14:12 +02:00
|
|
|
id: varg.id}
|
|
|
|
});
|
2012-03-23 19:49:01 -07:00
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, [], llfndecl, variant.node.id,
|
2012-02-08 10:05:44 +01:00
|
|
|
param_substs, none);
|
2012-03-11 12:06:05 +01:00
|
|
|
create_llargs_for_fn_args(fcx, no_self, fn_args);
|
2012-02-08 10:05:44 +01:00
|
|
|
let ty_param_substs = alt param_substs {
|
2012-02-09 11:17:11 +01:00
|
|
|
some(substs) { substs.tys }
|
2012-03-08 13:30:22 +01:00
|
|
|
none { [] }
|
2012-02-08 10:05:44 +01:00
|
|
|
};
|
2012-03-23 14:45:47 +01: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-03-23 14:45:47 +01:00
|
|
|
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, 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-05-03 22:31:38 -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-05-03 22:31:38 -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-05-03 22:31:38 -07:00
|
|
|
for vec::eachi(variant.node.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-02-21 14:20:18 +01:00
|
|
|
let llarg = alt check fcx.llargs.find(va.id) {
|
|
|
|
some(local_mem(x)) { x }
|
|
|
|
};
|
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
|
|
|
}
|
|
|
|
|
2011-06-15 11:19:50 -07:00
|
|
|
|
2011-01-21 12:09:25 -08:00
|
|
|
// FIXME: this should do some structural hash-consing to avoid
|
|
|
|
// duplicate constants. I think. Maybe LLVM has a magical mode
|
2012-06-07 14:37:36 -07:00
|
|
|
// that does so later on? (#2530)
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_const_expr(cx: @crate_ctxt, e: @ast::expr) -> ValueRef {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = cx.insn_ctxt("trans_const_expr");
|
2011-07-27 14:19:39 +02:00
|
|
|
alt e.node {
|
|
|
|
ast::expr_lit(lit) { ret trans_crate_lit(cx, *lit); }
|
2011-11-09 01:42:30 -08:00
|
|
|
ast::expr_binary(b, e1, e2) {
|
|
|
|
let te1 = trans_const_expr(cx, e1);
|
|
|
|
let te2 = trans_const_expr(cx, e2);
|
2012-02-21 21:01:33 -08:00
|
|
|
|
|
|
|
let te2 = cast_shift_const_rhs(b, te1, te2);
|
|
|
|
|
2011-11-09 01:42:30 -08:00
|
|
|
/* Neither type is bottom, and we expect them to be unified already,
|
|
|
|
* so the following is safe. */
|
2012-02-02 12:37:17 +01:00
|
|
|
let ty = ty::expr_ty(cx.tcx, e1);
|
2012-02-03 15:15:28 +01:00
|
|
|
let is_float = ty::type_is_fp(ty);
|
|
|
|
let signed = ty::type_is_signed(ty);
|
2011-11-09 01:42:30 -08:00
|
|
|
ret alt b {
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::add {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFAdd(te1, te2) }
|
|
|
|
else { llvm::LLVMConstAdd(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::subtract {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFSub(te1, te2) }
|
|
|
|
else { llvm::LLVMConstSub(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::mul {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFMul(te1, te2) }
|
|
|
|
else { llvm::LLVMConstMul(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::div {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFDiv(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSDiv(te1, te2) }
|
|
|
|
else { llvm::LLVMConstUDiv(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::rem {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFRem(te1, te2) }
|
|
|
|
else if signed { llvm::LLVMConstSRem(te1, te2) }
|
|
|
|
else { llvm::LLVMConstURem(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::and |
|
|
|
|
ast::or { cx.sess.span_unimpl(e.span, "binop logic"); }
|
|
|
|
ast::bitxor { llvm::LLVMConstXor(te1, te2) }
|
|
|
|
ast::bitand { llvm::LLVMConstAnd(te1, te2) }
|
|
|
|
ast::bitor { llvm::LLVMConstOr(te1, te2) }
|
2012-05-22 14:59:15 -07:00
|
|
|
ast::shl { llvm::LLVMConstShl(te1, te2) }
|
|
|
|
ast::shr {
|
|
|
|
if signed { llvm::LLVMConstAShr(te1, te2) }
|
|
|
|
else { llvm::LLVMConstLShr(te1, te2) }
|
|
|
|
}
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::eq |
|
|
|
|
ast::lt |
|
|
|
|
ast::le |
|
|
|
|
ast::ne |
|
|
|
|
ast::ge |
|
|
|
|
ast::gt { cx.sess.span_unimpl(e.span, "binop comparator"); }
|
2011-11-09 01:42:30 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
ast::expr_unary(u, e) {
|
|
|
|
let te = trans_const_expr(cx, e);
|
2012-02-02 12:37:17 +01:00
|
|
|
let ty = ty::expr_ty(cx.tcx, e);
|
2012-02-03 15:15:28 +01:00
|
|
|
let is_float = ty::type_is_fp(ty);
|
2011-11-09 01:42:30 -08:00
|
|
|
ret alt u {
|
|
|
|
ast::box(_) |
|
|
|
|
ast::uniq(_) |
|
2012-03-08 16:34:36 -08:00
|
|
|
ast::deref { cx.sess.span_bug(e.span,
|
2011-11-09 01:42:30 -08:00
|
|
|
"bad unop type in trans_const_expr"); }
|
2012-01-18 22:37:22 -08:00
|
|
|
ast::not { llvm::LLVMConstNot(te) }
|
|
|
|
ast::neg {
|
2011-11-09 01:42:30 -08:00
|
|
|
if is_float { llvm::LLVMConstFNeg(te) }
|
|
|
|
else { llvm::LLVMConstNeg(te) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-03-14 18:04:03 +01:00
|
|
|
ast::expr_cast(base, tp) {
|
|
|
|
let ety = ty::expr_ty(cx.tcx, e), llty = type_of(cx, ety);
|
|
|
|
let basety = ty::expr_ty(cx.tcx, base);
|
|
|
|
let v = trans_const_expr(cx, base);
|
|
|
|
alt check (cast_type_kind(basety), cast_type_kind(ety)) {
|
|
|
|
(cast_integral, cast_integral) {
|
|
|
|
let s = if ty::type_is_signed(basety) { True } else { False };
|
|
|
|
llvm::LLVMConstIntCast(v, llty, s)
|
|
|
|
}
|
|
|
|
(cast_integral, cast_float) {
|
|
|
|
if ty::type_is_signed(basety) { llvm::LLVMConstSIToFP(v, llty) }
|
|
|
|
else { llvm::LLVMConstUIToFP(v, llty) }
|
|
|
|
}
|
|
|
|
(cast_float, cast_float) { llvm::LLVMConstFPCast(v, llty) }
|
|
|
|
(cast_float, cast_integral) {
|
|
|
|
if ty::type_is_signed(ety) { llvm::LLVMConstFPToSI(v, llty) }
|
|
|
|
else { llvm::LLVMConstFPToUI(v, llty) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-04-04 15:02:25 -07:00
|
|
|
ast::expr_path(path) {
|
|
|
|
alt cx.tcx.def_map.find(e.id) {
|
|
|
|
some(ast::def_const(def_id)) {
|
|
|
|
// Don't know how to handle external consts
|
|
|
|
assert ast_util::is_local(def_id);
|
|
|
|
alt cx.tcx.items.get(def_id.node) {
|
|
|
|
ast_map::node_item(@{
|
|
|
|
node: ast::item_const(_, subexpr), _
|
|
|
|
}, _) {
|
|
|
|
// FIXME: Instead of recursing here to regenerate the values
|
|
|
|
// for other constants, we should just look up the
|
2012-06-07 14:37:36 -07:00
|
|
|
// already-defined value (#2530)
|
2012-04-04 15:02:25 -07:00
|
|
|
trans_const_expr(cx, subexpr)
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
cx.sess.span_bug(e.span, "expected item");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ { cx.sess.span_bug(e.span, "expected to find a const def") }
|
|
|
|
}
|
|
|
|
}
|
2011-11-09 01:42:30 -08:00
|
|
|
_ { cx.sess.span_bug(e.span,
|
|
|
|
"bad constant expression type in trans_const_expr"); }
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_const(ccx: @crate_ctxt, e: @ast::expr, id: ast::node_id) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_const");
|
2012-03-07 12:21:08 +01:00
|
|
|
let v = trans_const_expr(ccx, e);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2011-03-18 16:22:59 -07:00
|
|
|
// The scalars come back as 1st class LLVM vals
|
|
|
|
// which we have to stick into global constants.
|
2012-03-07 12:21:08 +01:00
|
|
|
let g = get_item_val(ccx, id);
|
|
|
|
llvm::LLVMSetInitializer(g, v);
|
|
|
|
llvm::LLVMSetGlobalConstant(g, True);
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
|
|
|
|
2012-04-02 10:48:32 -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,
|
2012-04-10 10:52:06 -07:00
|
|
|
parent_id: ast::def_id, sp: span) {
|
2012-04-02 10:48:32 -07:00
|
|
|
// Add ctor to the ctor map
|
|
|
|
ccx.class_ctors.insert(ctor_id, parent_id);
|
2012-04-10 10:52:06 -07:00
|
|
|
|
2012-04-02 10:48:32 -07:00
|
|
|
// 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.
|
2012-04-18 21:26:25 -07:00
|
|
|
let rslt_ty = ty::mk_class(ccx.tcx, parent_id,
|
|
|
|
dummy_substs(psubsts.tys));
|
|
|
|
|
2012-04-02 10:48:32 -07:00
|
|
|
// Make the fn context
|
|
|
|
let fcx = new_fn_ctxt_w_id(ccx, path, llctor_decl, ctor_id,
|
|
|
|
some(psubsts), some(sp));
|
|
|
|
create_llargs_for_fn_args(fcx, no_self, decl.inputs);
|
2012-05-14 14:24:16 -07:00
|
|
|
let mut bcx_top = top_scope_block(fcx, body.info());
|
2012-04-02 10:48:32 -07:00
|
|
|
let lltop = bcx_top.llbb;
|
|
|
|
bcx_top = copy_args_to_allocas(fcx, bcx_top, decl.inputs,
|
|
|
|
ty::ty_fn_args(node_id_type(bcx_top, ctor_id)));
|
|
|
|
|
|
|
|
// We *don't* want self to be passed to the ctor -- that
|
|
|
|
// wouldn't make sense
|
|
|
|
// So we initialize it here
|
2012-04-10 10:52:06 -07:00
|
|
|
|
2012-04-02 10:48:32 -07:00
|
|
|
let selfptr = alloc_ty(bcx_top, rslt_ty);
|
2012-05-15 17:59:55 -07:00
|
|
|
// If we have a dtor, we have a two-word representation with a drop
|
|
|
|
// flag, then a pointer to the class itself
|
|
|
|
let valptr = if option::is_some(ty::ty_dtor(bcx_top.tcx(),
|
|
|
|
parent_id)) {
|
|
|
|
// Initialize the drop flag
|
|
|
|
let one = C_u8(1u);
|
|
|
|
let flag = GEPi(bcx_top, selfptr, [0u, 0u]);
|
|
|
|
Store(bcx_top, one, flag);
|
|
|
|
// Select the pointer to the class itself
|
|
|
|
GEPi(bcx_top, selfptr, [0u, 1u])
|
|
|
|
}
|
|
|
|
else { selfptr };
|
|
|
|
|
2012-04-02 10:48:32 -07:00
|
|
|
// initialize fields to zero
|
2012-06-08 14:37:55 -07:00
|
|
|
let fields = ty::class_items_as_mutable_fields(bcx_top.tcx(), parent_id,
|
2012-04-18 21:26:25 -07:00
|
|
|
dummy_substs(psubsts.tys));
|
2012-04-02 10:48:32 -07:00
|
|
|
let mut bcx = bcx_top;
|
|
|
|
// Initialize fields to zero so init assignments can validly
|
|
|
|
// drop their LHS
|
2012-04-06 20:01:43 +02:00
|
|
|
for fields.each {|field|
|
2012-04-02 10:48:32 -07:00
|
|
|
let ix = field_idx_strict(bcx.tcx(), sp, field.ident, fields);
|
2012-05-28 20:52:11 -07:00
|
|
|
bcx = zero_mem(bcx, GEPi(bcx, valptr, [0u, ix]), field.mt.ty);
|
2012-04-02 10:48:32 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
// note we don't want to take *or* drop self.
|
|
|
|
fcx.llself = some({v: selfptr, t: rslt_ty});
|
|
|
|
|
|
|
|
// Translate the body of the ctor
|
|
|
|
bcx = trans_block(bcx_top, body, ignore);
|
|
|
|
let lval_res = {bcx: bcx, val: selfptr, kind: owned};
|
|
|
|
// Generate the return expression
|
|
|
|
bcx = store_temp_expr(bcx, INIT, fcx.llretptr, lval_res,
|
|
|
|
rslt_ty, true);
|
|
|
|
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-05-22 21:44:28 -04:00
|
|
|
body: ast::blk,
|
|
|
|
dtor_id: ast::node_id, substs: option<param_substs>,
|
2012-06-04 17:01:53 -07:00
|
|
|
hash_id: option<mono_id>, parent_id: ast::def_id)
|
|
|
|
-> 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 */
|
|
|
|
option::iter(substs) {|ss|
|
|
|
|
class_ty = ty::subst_tps(tcx, ss.tys, class_ty);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* The dtor takes a (null) output pointer, and a self argument,
|
|
|
|
and returns () */
|
|
|
|
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
|
|
|
|
T_ptr(type_of(ccx, class_ty))],
|
|
|
|
llvm::LLVMVoidType());
|
2012-06-04 17:01:53 -07:00
|
|
|
let s = get_dtor_symbol(ccx, path, dtor_id);
|
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 */
|
|
|
|
option::iter(hash_id) {|h_id|
|
|
|
|
ccx.monomorphized.insert(h_id, lldecl);
|
|
|
|
}
|
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-05-22 21:44:28 -04:00
|
|
|
body, lldecl, impl_self(class_ty), substs, dtor_id);
|
|
|
|
lldecl
|
2012-05-14 14:13:32 -07:00
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn trans_item(ccx: @crate_ctxt, item: ast::item) {
|
2012-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_item");
|
2012-02-15 15:42:35 +01:00
|
|
|
let path = alt check ccx.tcx.items.get(item.id) {
|
2012-02-03 09:53:37 +01:00
|
|
|
ast_map::node_item(_, p) { p }
|
|
|
|
};
|
2011-07-27 14:19:39 +02:00
|
|
|
alt item.node {
|
2011-12-22 17:49:54 +01:00
|
|
|
ast::item_fn(decl, tps, body) {
|
2012-03-08 13:30:22 +01:00
|
|
|
if decl.purity == ast::crust_fn {
|
|
|
|
let llfndecl = get_item_val(ccx, item.id);
|
2012-02-13 15:28:00 -08:00
|
|
|
native::trans_crust_fn(ccx, *path + [path_name(item.ident)],
|
|
|
|
decl, body, llfndecl, item.id);
|
2012-03-08 13:30:22 +01:00
|
|
|
} else if tps.len() == 0u {
|
|
|
|
let llfndecl = get_item_val(ccx, item.id);
|
|
|
|
trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
|
2012-03-23 19:49:01 -07:00
|
|
|
llfndecl, no_self, none, item.id);
|
2012-03-08 19:02:22 +01:00
|
|
|
} else {
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(body.node.stmts) {|stmt|
|
2012-03-08 19:02:22 +01:00
|
|
|
alt stmt.node {
|
|
|
|
ast::stmt_decl(@{node: ast::decl_item(i), _}, _) {
|
|
|
|
trans_item(ccx, *i);
|
|
|
|
}
|
|
|
|
_ {}
|
|
|
|
}
|
|
|
|
}
|
2010-09-22 17:05:38 -07:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-04-24 15:52:52 -07:00
|
|
|
ast::item_impl(tps, _rp, _, _, ms) {
|
2012-03-07 12:54:00 +01:00
|
|
|
impl::trans_impl(ccx, *path, item.ident, ms, tps);
|
2011-12-16 11:37:38 +01:00
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_res(decl, tps, body, dtor_id, ctor_id, _) {
|
2012-03-08 13:30:22 +01:00
|
|
|
if tps.len() == 0u {
|
|
|
|
let llctor_decl = get_item_val(ccx, ctor_id);
|
|
|
|
trans_res_ctor(ccx, *path, decl, ctor_id, none, llctor_decl);
|
2011-07-27 14:19:39 +02:00
|
|
|
|
2012-03-08 13:30:22 +01:00
|
|
|
let lldtor_decl = get_item_val(ccx, item.id);
|
|
|
|
trans_fn(ccx, *path + [path_name(item.ident)], decl, body,
|
2012-03-23 19:49:01 -07:00
|
|
|
lldtor_decl, no_self, none, dtor_id);
|
2012-03-08 13:30:22 +01:00
|
|
|
}
|
2011-07-27 14:19:39 +02: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-04-18 21:26:25 -07:00
|
|
|
ast::item_enum(variants, tps, _) {
|
2012-03-08 13:30:22 +01:00
|
|
|
if tps.len() == 0u {
|
|
|
|
let degen = variants.len() == 1u;
|
|
|
|
let vi = ty::enum_variants(ccx.tcx, local_def(item.id));
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut i = 0;
|
2012-03-27 15:14:12 +02:00
|
|
|
for vec::each(variants) {|variant|
|
2012-03-08 13:30:22 +01:00
|
|
|
if variant.node.args.len() > 0u {
|
2012-03-08 19:02:22 +01:00
|
|
|
let llfn = get_item_val(ccx, variant.node.id);
|
2012-03-08 13:30:22 +01:00
|
|
|
trans_enum_variant(ccx, item.id, variant,
|
|
|
|
vi[i].disr_val, degen,
|
|
|
|
none, llfn);
|
|
|
|
}
|
|
|
|
i += 1;
|
2012-02-08 10:05:44 +01:00
|
|
|
}
|
2011-01-21 12:09:25 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
}
|
2012-02-03 09:53:37 +01:00
|
|
|
ast::item_const(_, expr) { trans_const(ccx, expr, item.id); }
|
2011-11-10 09:14:53 -08:00
|
|
|
ast::item_native_mod(native_mod) {
|
2011-11-21 02:15:40 +08:00
|
|
|
let abi = alt attr::native_abi(item.attrs) {
|
|
|
|
either::right(abi_) { abi_ }
|
2012-02-03 09:53:37 +01:00
|
|
|
either::left(msg) { ccx.sess.span_fatal(item.span, msg) }
|
2011-11-21 02:15:40 +08:00
|
|
|
};
|
2012-02-13 14:59:05 -08:00
|
|
|
native::trans_native_mod(ccx, native_mod, abi);
|
2011-11-10 09:14:53 -08:00
|
|
|
}
|
2012-05-14 14:13:32 -07:00
|
|
|
ast::item_class(tps, _ifaces, items, ctor, m_dtor, _) {
|
2012-04-02 10:48:32 -07:00
|
|
|
if tps.len() == 0u {
|
|
|
|
let psubsts = {tys: ty::ty_params_to_tys(ccx.tcx, tps),
|
|
|
|
vtables: none,
|
|
|
|
bounds: @[]};
|
|
|
|
trans_class_ctor(ccx, *path, ctor.node.dec, ctor.node.body,
|
2012-04-18 21:26:25 -07:00
|
|
|
get_item_val(ccx, ctor.node.id), psubsts,
|
2012-04-10 10:52:06 -07:00
|
|
|
ctor.node.id, local_def(item.id), ctor.span);
|
2012-05-14 14:13:32 -07:00
|
|
|
option::iter(m_dtor) {|dtor|
|
2012-05-22 21:44:28 -04:00
|
|
|
trans_class_dtor(ccx, *path, dtor.node.body,
|
2012-06-04 17:01:53 -07:00
|
|
|
dtor.node.id, none, none, local_def(item.id));
|
2012-05-14 14:13:32 -07:00
|
|
|
};
|
2012-03-27 22:08:48 -07:00
|
|
|
}
|
2012-04-02 10:48:32 -07:00
|
|
|
// If there are ty params, the ctor will get monomorphized
|
2012-03-23 19:49:01 -07:00
|
|
|
|
2012-03-21 12:42:34 -07:00
|
|
|
// Translate methods
|
|
|
|
let (_, ms) = ast_util::split_class_items(items);
|
2012-03-28 18:50:33 -07:00
|
|
|
impl::trans_impl(ccx, *path, item.ident, ms, tps);
|
2012-03-03 17:49:23 -08:00
|
|
|
}
|
2011-07-27 14:19:39 +02:00
|
|
|
_ {/* fall through */ }
|
2010-09-22 17:05:38 -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-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_mod");
|
2012-03-27 15:14:12 +02: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.
|
2011-06-10 13:49:22 -07:00
|
|
|
ret 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-04-07 17:00:11 -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-02-14 15:21:53 -08:00
|
|
|
#debug["register_fn_fuller created fn %s for item %d with path %s",
|
|
|
|
val_str(ccx.tn, llfn), node_id, ast_map::path_to_str(path)];
|
|
|
|
|
2012-02-03 09:53:37 +01:00
|
|
|
let is_main = is_main_name(path) && !ccx.sess.building_library;
|
2011-08-19 15:16:48 -07:00
|
|
|
if is_main { create_main_wrapper(ccx, sp, llfn, node_type); }
|
2012-03-06 11:33:25 +01:00
|
|
|
llfn
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2011-08-17 20:31:55 -07:00
|
|
|
// Create a _rust_main(args: [str]) function which will be called from the
|
|
|
|
// runtime rust_start function
|
2012-03-14 17:31:16 -07:00
|
|
|
fn create_main_wrapper(ccx: @crate_ctxt, sp: span, main_llfn: ValueRef,
|
2011-08-19 15:16:48 -07:00
|
|
|
main_node_type: ty::t) {
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2011-08-13 00:09:25 -07:00
|
|
|
if ccx.main_fn != none::<ValueRef> {
|
2011-09-02 15:34:58 -07:00
|
|
|
ccx.sess.span_fatal(sp, "multiple 'main' functions");
|
2011-08-12 18:43:44 -07:00
|
|
|
}
|
|
|
|
|
2011-09-01 22:08:59 -07:00
|
|
|
let main_takes_argv =
|
2012-01-30 21:00:57 -08:00
|
|
|
// invariant!
|
2012-02-03 15:15:28 +01:00
|
|
|
alt ty::get(main_node_type).struct {
|
2012-02-14 09:10:47 +01:00
|
|
|
ty::ty_fn({inputs, _}) { inputs.len() != 0u }
|
2012-01-30 21:00:57 -08:00
|
|
|
_ { ccx.sess.span_fatal(sp, "main has a non-function type"); }
|
2011-08-19 15:16:48 -07:00
|
|
|
};
|
2011-08-12 18:43:44 -07:00
|
|
|
|
2012-01-27 12:55:21 +01:00
|
|
|
let llfn = create_main(ccx, main_llfn, main_takes_argv);
|
2011-08-17 16:50:49 -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-03-14 17:31:16 -07:00
|
|
|
fn create_main(ccx: @crate_ctxt, main_llfn: ValueRef,
|
2011-09-01 22:08:59 -07:00
|
|
|
takes_argv: bool) -> ValueRef {
|
2011-09-02 16:52:14 -07:00
|
|
|
let unit_ty = ty::mk_str(ccx.tcx);
|
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-02-15 11:25:39 -08:00
|
|
|
ty: ty::mk_vec(ccx.tcx, {ty: unit_ty, mutbl: ast::m_imm})};
|
2011-09-15 20:47:38 -07:00
|
|
|
let nt = ty::mk_nil(ccx.tcx);
|
2012-03-09 10:47:40 +01:00
|
|
|
let llfty = type_of_fn(ccx, [vecarg_ty], nt);
|
2011-09-27 18:42:06 -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-02-03 09:53:37 +01:00
|
|
|
let fcx = new_fn_ctxt(ccx, [], llfdecl, none);
|
2011-08-17 20:31:55 -07:00
|
|
|
|
2012-02-17 13:17:40 +01: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-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-03-15 09:47:03 -04:00
|
|
|
let mut args = [lloutputarg, llenvarg];
|
2012-01-18 19:29:37 +08:00
|
|
|
if takes_argv { args += [llvm::LLVMGetParam(llfdecl, 2 as c_uint)]; }
|
2011-09-27 18:42:06 -07:00
|
|
|
Call(bcx, main_llfn, args);
|
2011-08-17 17:49:54 -07:00
|
|
|
build_return(bcx);
|
2011-08-12 18:43:44 -07:00
|
|
|
|
|
|
|
finish_fn(fcx, lltop);
|
|
|
|
|
|
|
|
ret llfdecl;
|
|
|
|
}
|
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)]
|
2011-10-20 13:48:10 +02:00
|
|
|
fn main_name() -> str { ret "WinMain@16"; }
|
2012-06-07 21:38:25 -07:00
|
|
|
#[cfg(unix)]
|
2011-12-30 16:18:55 +08:00
|
|
|
fn main_name() -> str { ret "main"; }
|
2011-10-25 13:13:55 -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-03-14 15:10:34 -07:00
|
|
|
let llbb = str::as_c_str("top", {|buf|
|
2011-10-20 13:48:10 +02:00
|
|
|
llvm::LLVMAppendBasicBlock(llfn, buf)
|
|
|
|
});
|
|
|
|
let bld = *ccx.builder;
|
|
|
|
llvm::LLVMPositionBuilderAtEnd(bld, llbb);
|
|
|
|
let crate_map = ccx.crate_map;
|
2011-10-25 13:13:55 -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-04-09 12:02:16 +08:00
|
|
|
let start = decl_cdecl_fn(ccx.llmod, "rust_start", start_ty);
|
2012-04-09 14:38:53 +08:00
|
|
|
|
2012-01-18 19:29:37 +08: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-02-28 20:43:39 -08:00
|
|
|
llvm::LLVMBuildCall(bld, start, vec::unsafe::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
|
|
|
}
|
|
|
|
|
2011-06-29 18:44:38 -07:00
|
|
|
// Create a /real/ closure: this is like create_fn_pair, but creates a
|
|
|
|
// a fn value on the stack with a specified environment (which need not be
|
|
|
|
// on the stack).
|
2012-02-17 13:17:40 +01:00
|
|
|
fn create_real_fn_pair(cx: block, llfnty: TypeRef, llfn: ValueRef,
|
2011-07-27 14:19:39 +02:00
|
|
|
llenvptr: ValueRef) -> ValueRef {
|
2012-02-21 14:20:18 +01:00
|
|
|
let pair = alloca(cx, T_fn_pair(cx.ccx(), llfnty));
|
2011-09-28 15:57:38 +02:00
|
|
|
fill_fn_pair(cx, pair, llfn, llenvptr);
|
2011-06-29 18:44:38 -07:00
|
|
|
ret pair;
|
|
|
|
}
|
|
|
|
|
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-05-03 22:31:38 -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-05-03 22:31:38 -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-02-15 15:42:35 +01:00
|
|
|
*alt check ccx.tcx.items.get(i.id) {
|
|
|
|
ast_map::node_item(_, p) { p }
|
2012-02-03 09:53:37 +01:00
|
|
|
} + [path_name(i.ident)]
|
|
|
|
}
|
|
|
|
|
2012-06-04 17:01:53 -07:00
|
|
|
/* If there's already a symbol for the dtor with <id>, 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) -> str {
|
|
|
|
alt ccx.item_symbols.find(id) {
|
|
|
|
some(s) { s }
|
|
|
|
none {
|
|
|
|
let s = mangle_exported_name(ccx, path +
|
2012-06-10 00:49:59 -07:00
|
|
|
[path_name(@ccx.names("dtor"))], ty::node_id_to_type(ccx.tcx, id));
|
2012-06-04 17:01:53 -07:00
|
|
|
ccx.item_symbols.insert(id, s);
|
|
|
|
s
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn get_item_val(ccx: @crate_ctxt, id: ast::node_id) -> ValueRef {
|
2012-05-22 21:44:28 -04:00
|
|
|
let tcx = ccx.tcx;
|
2012-03-07 12:21:08 +01:00
|
|
|
alt ccx.item_vals.find(id) {
|
|
|
|
some(v) { v }
|
|
|
|
none {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut exprt = false;
|
2012-03-07 12:21:08 +01:00
|
|
|
let val = alt check ccx.tcx.items.get(id) {
|
|
|
|
ast_map::node_item(i, pth) {
|
|
|
|
let my_path = *pth + [path_name(i.ident)];
|
|
|
|
alt check i.node {
|
|
|
|
ast::item_const(_, _) {
|
|
|
|
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-03-14 15:10:34 -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-03-09 10:47:40 +01:00
|
|
|
ast::item_fn(decl, _, _) {
|
2012-03-07 12:21:08 +01:00
|
|
|
let llfn = if decl.purity != ast::crust_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 {
|
|
|
|
native::register_crust_fn(ccx, i.span, my_path, i.id)
|
|
|
|
};
|
|
|
|
set_inline_hint_if_appr(i.attrs, llfn);
|
|
|
|
llfn
|
|
|
|
}
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_res(_, _, _, dtor_id, _, _) {
|
2012-03-07 12:21:08 +01:00
|
|
|
// Note that the destructor is associated with the item's id,
|
|
|
|
// not the dtor_id. This is a bit counter-intuitive, but
|
|
|
|
// simplifies ty_res, which would have to carry around two
|
|
|
|
// def_ids otherwise -- one to identify the type, and one to
|
|
|
|
// find the dtor symbol.
|
|
|
|
let t = ty::node_id_to_type(ccx.tcx, dtor_id);
|
2012-06-10 00:49:59 -07:00
|
|
|
register_fn_full(ccx, i.span, my_path + [path_name(@"dtor")],
|
2012-03-20 15:15:57 -07:00
|
|
|
i.id, t)
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
2011-01-05 15:31:35 -08:00
|
|
|
}
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
|
|
|
ast_map::node_method(m, impl_id, pth) {
|
2012-03-20 13:19:33 +01:00
|
|
|
exprt = true;
|
2012-03-07 12:21:08 +01:00
|
|
|
let mty = ty::node_id_to_type(ccx.tcx, id);
|
2012-06-10 00:49:59 -07:00
|
|
|
let pth = *pth + [path_name(@ccx.names("meth")),
|
2012-03-07 12:21:08 +01:00
|
|
|
path_name(m.ident)];
|
2012-03-20 15:15:57 -07:00
|
|
|
let llfn = register_fn_full(ccx, m.span, pth, id, mty);
|
2012-03-07 12:21:08 +01:00
|
|
|
set_inline_hint_if_appr(m.attrs, llfn);
|
|
|
|
llfn
|
|
|
|
}
|
|
|
|
ast_map::node_native_item(ni, _, pth) {
|
2012-03-20 13:19:33 +01:00
|
|
|
exprt = true;
|
2012-03-23 15:05:16 +01:00
|
|
|
register_fn(ccx, ni.span, *pth + [path_name(ni.ident)], ni.id)
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
2012-04-10 10:52:06 -07:00
|
|
|
ast_map::node_ctor(nm, tps, ct, pt) {
|
|
|
|
let my_path = *pt + [path_name(nm)];
|
|
|
|
alt ct {
|
|
|
|
ast_map::res_ctor(_,_,sp) {
|
|
|
|
let llctor = register_fn(ccx, sp, my_path, id);
|
2012-03-07 12:21:08 +01:00
|
|
|
set_inline_hint(llctor);
|
|
|
|
llctor
|
|
|
|
}
|
2012-04-10 10:52:06 -07:00
|
|
|
ast_map::class_ctor(ctor, _) {
|
|
|
|
register_fn(ccx, ctor.span, my_path, ctor.node.id)
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2012-05-14 14:13:32 -07:00
|
|
|
ast_map::node_dtor(tps, 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);
|
|
|
|
let lldty = T_fn([T_ptr(type_of(ccx, ty::mk_nil(tcx))),
|
|
|
|
T_ptr(type_of(ccx, class_ty))],
|
|
|
|
llvm::LLVMVoidType());
|
2012-06-04 17:01:53 -07:00
|
|
|
let s = get_dtor_symbol(ccx, *pt, dt.node.id);
|
|
|
|
|
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-03-07 12:21:08 +01:00
|
|
|
ast_map::node_variant(v, enm, pth) {
|
|
|
|
assert v.node.args.len() != 0u;
|
|
|
|
let pth = *pth + [path_name(enm.ident), path_name(v.node.name)];
|
|
|
|
let llfn = alt check enm.node {
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_enum(_, _, _) {
|
2012-03-20 15:15:57 -07:00
|
|
|
register_fn(ccx, v.span, pth, id)
|
2012-03-07 12:21:08 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
set_inline_hint(llfn);
|
|
|
|
llfn
|
|
|
|
}
|
|
|
|
};
|
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
|
|
|
}
|
|
|
|
}
|
|
|
|
|
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-03-22 13:44:20 -07:00
|
|
|
let _icx = ccx.insn_ctxt("trans_constant");
|
2011-07-27 14:19:39 +02:00
|
|
|
alt it.node {
|
2012-04-18 21:26:25 -07:00
|
|
|
ast::item_enum(variants, _, _) {
|
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-03-27 15:14:12 +02:00
|
|
|
for vec::each(variants) {|variant|
|
2012-02-03 09:53:37 +01:00
|
|
|
let p = path + [path_name(variant.node.name),
|
2012-06-10 00:49:59 -07:00
|
|
|
path_name(@"discrim")];
|
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-03-14 15:10:34 -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
|
|
|
}
|
|
|
|
_ { }
|
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(@{
|
|
|
|
visit_item: bind trans_constant(ccx, _)
|
|
|
|
with *visit::default_simple_visitor()
|
|
|
|
}));
|
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();
|
2011-10-14 17:00:17 -07:00
|
|
|
ret 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 {
|
2011-10-14 17:00:17 -07:00
|
|
|
ret llvm::LLVMConstPtrToInt(v, ccx.int_type);
|
|
|
|
}
|
2010-09-27 13:43:53 -07:00
|
|
|
|
2011-09-02 15:34:58 -07:00
|
|
|
fn declare_intrinsics(llmod: ModuleRef) -> hashmap<str, ValueRef> {
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memmove32_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i32(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memmove64_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_ptr(T_i8()), T_i64(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memset32_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_i8(), T_i32(), T_i32(), T_i1()];
|
2011-08-04 16:20:09 -07:00
|
|
|
let T_memset64_args: [TypeRef] =
|
2011-08-19 15:16:48 -07:00
|
|
|
[T_ptr(T_i8()), T_i8(), T_i64(), T_i32(), T_i1()];
|
|
|
|
let T_trap_args: [TypeRef] = [];
|
2012-06-05 18:41:18 -07:00
|
|
|
let T_frameaddress_args: [TypeRef] = [T_i32()];
|
2011-08-17 19:11:01 -07:00
|
|
|
let gcroot =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.gcroot",
|
2011-08-19 15:16:48 -07:00
|
|
|
T_fn([T_ptr(T_ptr(T_i8())), T_ptr(T_i8())], T_void()));
|
2011-08-10 17:59:33 -07:00
|
|
|
let gcread =
|
2011-09-02 15:34:58 -07:00
|
|
|
decl_cdecl_fn(llmod, "llvm.gcread",
|
2011-08-19 15:16:48 -07:00
|
|
|
T_fn([T_ptr(T_i8()), T_ptr(T_ptr(T_i8()))], T_void()));
|
2011-07-27 14:19:39 +02:00
|
|
|
let memmove32 =
|
2011-09-02 15:34:58 -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 =
|
2011-09-02 15:34:58 -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 =
|
2011-09-02 15:34:58 -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 =
|
2011-09-02 15:34:58 -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()));
|
2011-09-02 15:34:58 -07:00
|
|
|
let trap = decl_cdecl_fn(llmod, "llvm.trap", T_fn(T_trap_args, T_void()));
|
2012-06-05 18:41:18 -07:00
|
|
|
let frameaddress = decl_cdecl_fn(llmod, "llvm.frameaddress",
|
|
|
|
T_fn(T_frameaddress_args,
|
|
|
|
T_ptr(T_i8())));
|
2012-03-14 12:07:23 -07:00
|
|
|
let intrinsics = str_hash::<ValueRef>();
|
2011-09-02 15:34:58 -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);
|
2012-06-05 18:41:18 -07:00
|
|
|
intrinsics.insert("llvm.frameaddress", frameaddress);
|
2010-11-25 17:45:26 -08:00
|
|
|
ret intrinsics;
|
2010-11-14 11:21:49 -08:00
|
|
|
}
|
|
|
|
|
2011-11-15 21:11:22 -05:00
|
|
|
fn declare_dbg_intrinsics(llmod: ModuleRef,
|
|
|
|
intrinsics: hashmap<str, ValueRef>) {
|
|
|
|
let declare =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.dbg.declare",
|
|
|
|
T_fn([T_metadata(), T_metadata()], T_void()));
|
|
|
|
let value =
|
|
|
|
decl_cdecl_fn(llmod, "llvm.dbg.value",
|
|
|
|
T_fn([T_metadata(), T_i64(), T_metadata()], T_void()));
|
|
|
|
intrinsics.insert("llvm.dbg.declare", declare);
|
|
|
|
intrinsics.insert("llvm.dbg.value", value);
|
|
|
|
}
|
|
|
|
|
2012-02-17 13:17:40 +01:00
|
|
|
fn trap(bcx: block) {
|
2011-08-19 15:16:48 -07:00
|
|
|
let v: [ValueRef] = [];
|
2012-02-21 14:20:18 +01:00
|
|
|
alt bcx.ccx().intrinsics.find("llvm.trap") {
|
2011-08-30 09:59:30 +02:00
|
|
|
some(x) { Call(bcx, x, v); }
|
2012-02-21 14:20:18 +01: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-03-14 17:31:16 -07:00
|
|
|
fn create_module_map(ccx: @crate_ctxt) -> ValueRef {
|
2011-10-14 17:00:17 -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-03-14 15:10:34 -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-03-15 09:47:03 -04:00
|
|
|
let mut elts: [ValueRef] = [];
|
2012-04-23 13:42:15 +02:00
|
|
|
for ccx.module_data.each {|key, val|
|
2011-10-25 13:13:55 -07:00
|
|
|
let elt = C_struct([p2i(ccx, C_cstr(ccx, key)),
|
|
|
|
p2i(ccx, val)]);
|
2011-08-19 15:16:48 -07:00
|
|
|
elts += [elt];
|
2011-10-21 12:21:27 +02:00
|
|
|
};
|
2011-10-25 13:13:55 -07:00
|
|
|
let term = C_struct([C_int(ccx, 0), C_int(ccx, 0)]);
|
2011-08-19 15:16:48 -07:00
|
|
|
elts += [term];
|
2011-05-12 17:24:54 +02:00
|
|
|
llvm::LLVMSetInitializer(map, C_array(elttype, elts));
|
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
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
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-06-10 00:49:59 -07:00
|
|
|
*mapmeta.name + "_" + *mapmeta.vers + "_" + mapmeta.extras_hash
|
2012-04-06 18:45:49 +08:00
|
|
|
} else { "toplevel" };
|
2011-10-20 13:48:10 +02:00
|
|
|
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);
|
|
|
|
let maptype = T_struct([int_type, arrtype]);
|
2012-03-14 15:10:34 -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);
|
2011-10-20 13:48:10 +02:00
|
|
|
ret map;
|
|
|
|
}
|
|
|
|
|
2012-03-14 17:31:16 -07:00
|
|
|
fn fill_crate_map(ccx: @crate_ctxt, map: ValueRef) {
|
2012-03-15 09:47:03 -04:00
|
|
|
let mut subcrates: [ValueRef] = [];
|
|
|
|
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);
|
|
|
|
let nm = "_rust_crate_map_" + cdata.name +
|
2012-06-10 00:49:59 -07:00
|
|
|
"_" + *cstore::get_crate_vers(cstore, i) +
|
|
|
|
"_" + *cstore::get_crate_hash(cstore, i);
|
2012-03-14 15:10:34 -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
|
|
|
});
|
2011-10-25 13:13:55 -07:00
|
|
|
subcrates += [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;
|
|
|
|
}
|
2011-10-14 17:00:17 -07:00
|
|
|
subcrates += [C_int(ccx, 0)];
|
2011-10-25 13:13:55 -07:00
|
|
|
llvm::LLVMSetInitializer(map, C_struct(
|
|
|
|
[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 =
|
|
|
|
bind astencode::encode_inlined_item(_, _, _, _, cx.maps);
|
|
|
|
|
2012-05-16 21:50:17 -07:00
|
|
|
ret {
|
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-05-16 21:50:17 -07:00
|
|
|
reexports: reexports(cx),
|
2012-05-16 22:28:01 -07:00
|
|
|
impl_map: impl_map(cx, _),
|
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
|
|
|
};
|
|
|
|
|
|
|
|
fn reexports(cx: @crate_ctxt) -> [(str, ast::def_id)] {
|
|
|
|
let mut reexports = [];
|
|
|
|
for cx.exp_map.each {|exp_id, defs|
|
|
|
|
for defs.each {|def|
|
|
|
|
if !def.reexp { cont; }
|
|
|
|
let path = alt check cx.tcx.items.get(exp_id) {
|
|
|
|
ast_map::node_export(_, path) {
|
|
|
|
ast_map::path_to_str(*path)
|
|
|
|
}
|
|
|
|
};
|
|
|
|
reexports += [(path, def.id)];
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ret reexports;
|
2012-05-13 17:01:52 -07:00
|
|
|
}
|
|
|
|
|
2012-05-16 22:28:01 -07:00
|
|
|
fn impl_map(cx: @crate_ctxt,
|
|
|
|
id: ast::node_id) -> [(ast::ident, ast::def_id)] {
|
2012-05-21 09:37:34 -07:00
|
|
|
alt *cx.maps.impl_map.get(id) {
|
2012-05-16 22:28:01 -07:00
|
|
|
list::cons(impls, @list::nil) {
|
|
|
|
(*impls).map {|i|
|
|
|
|
(i.ident, i.did)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
_ {
|
|
|
|
cx.sess.bug(#fmt("encode_info_for_mod: empty impl_map \
|
|
|
|
entry for %?", id));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
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-01-12 17:59:49 +01:00
|
|
|
if !cx.sess.building_library { ret; }
|
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-01-27 13:17:06 +01:00
|
|
|
let llconst = C_struct([llmeta]);
|
2012-03-15 09:47:03 -04: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-03-14 15:10:34 -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-03-14 15:10:34 -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);
|
2011-08-19 15:16:48 -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-02-10 11:32:03 +01:00
|
|
|
mk_global(ccx, "rust_abi_version", C_uint(ccx, abi::abi_version),
|
2011-08-20 14:22:09 -07:00
|
|
|
false);
|
|
|
|
}
|
|
|
|
|
2011-09-12 11:27:30 +02:00
|
|
|
fn trans_crate(sess: session::session, crate: @ast::crate, tcx: ty::ctxt,
|
2012-05-13 17:01:52 -07:00
|
|
|
output: str, emap: resolve::exp_map,
|
2012-05-14 17:46:45 -07:00
|
|
|
maps: astencode::maps)
|
2012-05-17 16:17:11 -07:00
|
|
|
-> (ModuleRef, link_meta) {
|
2012-03-12 15:52:30 -07:00
|
|
|
let sha = std::sha1::sha1();
|
2011-11-07 22:59:21 +08:00
|
|
|
let link_meta = link::build_link_meta(sess, *crate, output, sha);
|
2012-03-20 12:28:46 +01:00
|
|
|
let reachable = reachable::find_reachable(crate.node.module, emap, tcx,
|
|
|
|
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-06-10 00:49:59 -07:00
|
|
|
let llmod_id = *link_meta.name + ".rc";
|
2011-12-05 14:56:11 +08:00
|
|
|
|
2012-03-14 15:10:34 -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,
|
2011-09-02 15:34:58 -07:00
|
|
|
{|buf| llvm::LLVMSetDataLayout(llmod, buf) });
|
|
|
|
let _: () =
|
2012-03-14 15:10:34 -07:00
|
|
|
str::as_c_str(targ_triple,
|
2011-09-02 15:34:58 -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-01-13 09:32:05 +01: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-01-13 09:32:05 +01: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-03-21 18:56:20 -04:00
|
|
|
option::some(debuginfo::mk_ctxt(llmod_id))
|
2011-12-09 11:32:23 -05:00
|
|
|
} else {
|
|
|
|
option::none
|
|
|
|
};
|
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-03-14 12:07:23 -07:00
|
|
|
externs: str_hash::<ValueRef>(),
|
2011-07-27 14:19:39 +02:00
|
|
|
intrinsics: intrinsics,
|
2012-03-14 12:07:23 -07:00
|
|
|
item_vals: int_hash::<ValueRef>(),
|
2011-12-15 18:42:27 +08:00
|
|
|
exp_map: emap,
|
2012-03-20 12:28:46 +01:00
|
|
|
reachable: reachable,
|
2012-03-14 12:07:23 -07:00
|
|
|
item_symbols: int_hash::<str>(),
|
2012-03-26 18:35:18 -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-05-23 00:45:18 -07:00
|
|
|
discrims: ast_util::new_def_hash::<ValueRef>(),
|
2012-03-14 12:07:23 -07:00
|
|
|
discrim_symbols: int_hash::<str>(),
|
2011-12-22 14:24:36 +01:00
|
|
|
tydescs: ty::new_ty_hash(),
|
2012-05-23 00:38:39 -07:00
|
|
|
external: ast_util::new_def_hash(),
|
2012-03-14 12:07:23 -07:00
|
|
|
monomorphized: map::hashmap(hash_mono_id, {|a, b| a == b}),
|
2012-05-23 00:45:18 -07:00
|
|
|
monomorphizing: ast_util::new_def_hash(),
|
2012-05-23 00:38:39 -07:00
|
|
|
type_use_cache: ast_util::new_def_hash(),
|
2012-03-08 16:10:25 +01:00
|
|
|
vtables: map::hashmap(hash_mono_id, {|a, b| a == b}),
|
2012-04-21 13:23:25 -07:00
|
|
|
const_cstr_cache: map::str_hash(),
|
2012-03-14 12:07:23 -07:00
|
|
|
module_data: str_hash::<ValueRef>(),
|
2011-12-22 14:24:36 +01:00
|
|
|
lltypes: ty::new_ty_hash(),
|
2012-01-13 09:32:05 +01:00
|
|
|
names: new_namegen(),
|
2011-07-27 14:19:39 +02:00
|
|
|
sha: sha,
|
2011-12-22 14:24:36 +01:00
|
|
|
type_sha1s: ty::new_ty_hash(),
|
|
|
|
type_short_names: ty::new_ty_hash(),
|
2012-03-20 14:21:02 -07:00
|
|
|
all_llvm_symbols: str_hash::<()>(),
|
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,
|
|
|
|
llvm_insn_ctxt: @mut [],
|
2012-03-22 13:44:20 -07:00
|
|
|
llvm_insns: str_hash(),
|
2012-03-26 18:35:18 -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),
|
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-02-01 18:52:08 -08:00
|
|
|
dbg_cx: dbg_cx,
|
2012-04-10 10:52:06 -07:00
|
|
|
class_ctors: int_hash::<ast::def_id>(),
|
2012-03-26 18:35:18 -07:00
|
|
|
mut do_not_commit_warning_issued: false};
|
2012-03-22 13:44:20 -07:00
|
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
let _icx = ccx.insn_ctxt("data");
|
|
|
|
trans_constants(ccx, crate);
|
|
|
|
}
|
|
|
|
|
|
|
|
{
|
|
|
|
let _icx = ccx.insn_ctxt("text");
|
|
|
|
trans_mod(ccx, crate.node.module);
|
|
|
|
}
|
|
|
|
|
2011-10-20 13:48:10 +02:00
|
|
|
fill_crate_map(ccx, crate_map);
|
2011-05-12 15:42:12 -07:00
|
|
|
emit_tydescs(ccx);
|
2012-02-10 11:32:03 +01:00
|
|
|
gen_shape_tables(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-05-17 21:53:49 -07:00
|
|
|
if ccx.sess.stats() {
|
2012-03-22 13:44:20 -07:00
|
|
|
io::println("--- trans stats ---");
|
|
|
|
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-04-24 15:18:24 -07:00
|
|
|
// FIXME (#2280): this temporary shouldn't be
|
|
|
|
// necessary, but seems to be, for borrowing.
|
|
|
|
let times = copy *ccx.stats.fn_times;
|
|
|
|
for vec::each(times) {|timing|
|
2012-03-22 13:44:20 -07:00
|
|
|
io::println(#fmt("time: %s took %d ms", timing.ident,
|
|
|
|
timing.time));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-05-17 21:53:49 -07:00
|
|
|
if ccx.sess.count_llvm_insns() {
|
2012-04-23 13:42:15 +02:00
|
|
|
for ccx.stats.llvm_insns.each { |k, v|
|
2012-03-22 13:44:20 -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
|
|
|
}
|
2011-12-03 00:51:59 +08:00
|
|
|
ret (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:
|
|
|
|
//
|