Update trans to use type to decide when to move, not the moves table (simpler

for cases where it's hard to decide what id to use for the lookup); modify
irrefutable bindings code to move or copy depending on the type, rather than
threading through a flag. Also updates how local variables and arguments are
registered. These changes were hard to isolate.
This commit is contained in:
Niko Matsakis 2013-06-20 15:23:52 -04:00
parent 41efcdf299
commit 2d3262ca7b
8 changed files with 386 additions and 274 deletions

View File

@ -53,7 +53,6 @@ pub struct Maps {
method_map: middle::typeck::method_map,
vtable_map: middle::typeck::vtable_map,
write_guard_map: middle::borrowck::write_guard_map,
moves_map: middle::moves::MovesMap,
capture_map: middle::moves::CaptureMap,
}
@ -952,12 +951,6 @@ fn encode_side_tables_for_id(ecx: &e::EncodeContext,
}
}
if maps.moves_map.contains(&id) {
do ebml_w.tag(c::tag_table_moves_map) |ebml_w| {
ebml_w.id(id);
}
}
{
let r = maps.capture_map.find(&id);
for r.iter().advance |&cap_vars| {
@ -1121,9 +1114,7 @@ fn decode_side_tables(xcx: @ExtendedDecodeContext,
xcx.dcx.tcx.sess.bug(
fmt!("unknown tag found in side tables: %x", tag));
}
Some(value) => if value == c::tag_table_moves_map {
dcx.maps.moves_map.insert(id);
} else {
Some(value) => {
let val_doc = entry_doc.get(c::tag_table_val as uint);
let mut val_dsr = reader::Decoder(val_doc);
let val_dsr = &mut val_dsr;

View File

@ -187,7 +187,6 @@ pub fn lookup_const_by_id(tcx: ty::ctxt,
method_map: @mut HashMap::new(),
vtable_map: @mut HashMap::new(),
write_guard_map: @mut HashSet::new(),
moves_map: @mut HashSet::new(),
capture_map: @mut HashMap::new()
};
match csearch::maybe_get_item_ast(tcx, def_id,

View File

@ -316,7 +316,7 @@ pub fn variant_opt(bcx: block, pat_id: ast::node_id)
}
pub enum TransBindingMode {
TrByValue(/*ismove:*/ bool, /*llbinding:*/ ValueRef),
TrByValue(/*llbinding:*/ ValueRef),
TrByRef,
}
@ -1138,18 +1138,11 @@ fn store_non_ref_bindings(bcx: block,
let mut bcx = bcx;
for bindings_map.each_value |&binding_info| {
match binding_info.trmode {
TrByValue(is_move, lldest) => {
TrByValue(lldest) => {
let llval = Load(bcx, binding_info.llmatch); // get a T*
let datum = Datum {val: llval, ty: binding_info.ty,
mode: ByRef(ZeroMem)};
bcx = {
if is_move {
datum.move_to(bcx, INIT, lldest)
} else {
datum.copy_to(bcx, INIT, lldest)
}
};
bcx = datum.store_to(bcx, INIT, lldest);
do opt_temp_cleanups.mutate |temp_cleanups| {
add_clean_temp_mem(bcx, lldest, binding_info.ty);
temp_cleanups.push(lldest);
@ -1181,7 +1174,7 @@ fn insert_lllocals(bcx: block,
let llval = match binding_info.trmode {
// By value bindings: use the stack slot that we
// copied/moved the value into
TrByValue(_, lldest) => {
TrByValue(lldest) => {
if add_cleans {
add_clean(bcx, lldest, binding_info.ty);
}
@ -1245,7 +1238,7 @@ pub fn compile_guard(bcx: block,
let mut bcx = bcx;
for data.bindings_map.each_value |&binding_info| {
match binding_info.trmode {
TrByValue(_, llval) => {
TrByValue(llval) => {
bcx = glue::drop_ty(bcx, llval, binding_info.ty);
}
TrByRef => {}
@ -1737,53 +1730,204 @@ pub enum IrrefutablePatternBindingMode {
BindArgument
}
// Not match-related, but similar to the pattern-munging code above
pub fn bind_irrefutable_pat(bcx: block,
pat: @ast::pat,
val: ValueRef,
make_copy: bool,
binding_mode: IrrefutablePatternBindingMode)
-> block {
let _icx = push_ctxt("match::bind_irrefutable_pat");
let ccx = bcx.fcx.ccx;
pub fn store_local(bcx: block,
pat: @ast::pat,
opt_init_expr: Option<@ast::expr>)
-> block {
/*!
* Generates code for a local variable declaration like
* `let <pat>;` or `let <pat> = <opt_init_expr>`.
*/
let mut bcx = bcx;
// Necessary since bind_irrefutable_pat is called outside trans_match
match pat.node {
ast::pat_ident(_, _, ref inner) => {
if pat_is_variant_or_struct(bcx.tcx().def_map, pat) {
return bcx;
return match opt_init_expr {
Some(init_expr) => {
// Optimize the "let x = expr" case. This just writes
// the result of evaluating `expr` directly into the alloca
// for `x`. Often the general path results in similar or the
// same code post-optimization, but not always. In particular,
// in unsafe code, you can have expressions like
//
// let x = intrinsics::uninit();
//
// In such cases, the more general path is unsafe, because
// it assumes it is matching against a valid value.
match simple_identifier(pat) {
Some(path) => {
return mk_binding_alloca(
bcx, pat.id, path, BindLocal,
|bcx, _, llval| expr::trans_into(bcx, init_expr,
expr::SaveIn(llval)));
}
None => {}
}
if make_copy {
let binding_ty = node_id_type(bcx, pat.id);
let datum = Datum {val: val, ty: binding_ty,
mode: ByRef(RevokeClean)};
let scratch = scratch_datum(bcx, binding_ty, false);
datum.copy_to_datum(bcx, INIT, scratch);
match binding_mode {
BindLocal => {
bcx.fcx.lllocals.insert(pat.id, scratch.val);
}
BindArgument => {
bcx.fcx.llargs.insert(pat.id, scratch.val);
}
}
add_clean(bcx, scratch.val, binding_ty);
// General path.
let init_datum =
unpack_datum!(
bcx,
expr::trans_to_datum(bcx, init_expr));
if ty::type_is_bot(expr_ty(bcx, init_expr)) {
create_dummy_locals(bcx, pat)
} else {
match binding_mode {
BindLocal => {
bcx.fcx.lllocals.insert(pat.id, val);
}
BindArgument => {
bcx.fcx.llargs.insert(pat.id, val);
}
if bcx.sess().asm_comments() {
add_comment(bcx, "creating zeroable ref llval");
}
let llptr = init_datum.to_zeroable_ref_llval(bcx);
return bind_irrefutable_pat(bcx, pat, llptr, BindLocal);
}
}
None => {
create_dummy_locals(bcx, pat)
}
};
fn create_dummy_locals(mut bcx: block, pat: @ast::pat) -> block {
// create dummy memory for the variables if we have no
// value to store into them immediately
let tcx = bcx.tcx();
do pat_bindings(tcx.def_map, pat) |_, p_id, _, path| {
bcx = mk_binding_alloca(
bcx, p_id, path, BindLocal,
|bcx, var_ty, llval| { zero_mem(bcx, llval, var_ty); bcx });
}
bcx
}
}
pub fn store_arg(mut bcx: block,
pat: @ast::pat,
llval: ValueRef)
-> block {
/*!
* Generates code for argument patterns like `fn foo(<pat>: T)`.
* Creates entries in the `llargs` map for each of the bindings
* in `pat`.
*
* # Arguments
*
* - `pat` is the argument pattern
* - `llval` is a pointer to the argument value (in other words,
* if the argument type is `T`, then `llval` is a `T*`). In some
* cases, this code may zero out the memory `llval` points at.
*/
// We always need to cleanup the argument as we exit the fn scope.
// Note that we cannot do it before for fear of a fn like
// fn getaddr(~ref x: ~uint) -> *uint {....}
// (From test `run-pass/func-arg-ref-pattern.rs`)
let arg_ty = node_id_type(bcx, pat.id);
add_clean(bcx, llval, arg_ty);
match simple_identifier(pat) {
Some(_) => {
// Optimized path for `x: T` case. This just adopts
// `llval` wholesale as the pointer for `x`, avoiding the
// general logic which may copy out of `llval`.
bcx.fcx.llargs.insert(pat.id, llval);
}
None => {
// General path. Copy out the values that are used in the
// pattern.
bcx = bind_irrefutable_pat(bcx, pat, llval, BindArgument);
}
}
return bcx;
}
fn mk_binding_alloca(mut bcx: block,
p_id: ast::node_id,
path: @ast::Path,
binding_mode: IrrefutablePatternBindingMode,
populate: &fn(block, ty::t, ValueRef) -> block) -> block {
let var_ty = node_id_type(bcx, p_id);
let ident = ast_util::path_to_ident(path);
let llval = alloc_ty(bcx, var_ty, bcx.ident(ident));
bcx = populate(bcx, var_ty, llval);
let llmap = match binding_mode {
BindLocal => bcx.fcx.lllocals,
BindArgument => bcx.fcx.llargs
};
llmap.insert(p_id, llval);
add_clean(bcx, llval, var_ty);
return bcx;
}
fn bind_irrefutable_pat(bcx: block,
pat: @ast::pat,
val: ValueRef,
binding_mode: IrrefutablePatternBindingMode)
-> block {
/*!
* A simple version of the pattern matching code that only handles
* irrefutable patterns. This is used in let/argument patterns,
* not in match statements. Unifying this code with the code above
* sounds nice, but in practice it produces very inefficient code,
* since the match code is so much more general. In most cases,
* LLVM is able to optimize the code, but it causes longer compile
* times and makes the generated code nigh impossible to read.
*
* # Arguments
* - bcx: starting basic block context
* - pat: the irrefutable pattern being matched.
* - val: a pointer to the value being matched. If pat matches a value
* of type T, then this is a T*. If the value is moved from `pat`,
* then `*pat` will be zeroed; otherwise, it's existing cleanup
* applies.
* - binding_mode: is this for an argument or a local variable?
*/
debug!("bind_irrefutable_pat(bcx=%s, pat=%s, val=%s, binding_mode=%?)",
bcx.to_str(),
pat_to_str(pat, bcx.sess().intr()),
val_str(bcx.ccx().tn, val),
binding_mode);
if bcx.sess().asm_comments() {
add_comment(bcx, fmt!("bind_irrefutable_pat(pat=%s)",
pat_to_str(pat, bcx.sess().intr())));
}
let _indenter = indenter();
let _icx = bcx.insn_ctxt("alt::bind_irrefutable_pat");
let mut bcx = bcx;
let tcx = bcx.tcx();
let ccx = bcx.ccx();
match pat.node {
ast::pat_ident(pat_binding_mode, path, inner) => {
if pat_is_binding(tcx.def_map, pat) {
// Allocate the stack slot where the value of this
// binding will live and place it into the appropriate
// map.
bcx = mk_binding_alloca(
bcx, pat.id, path, binding_mode,
|bcx, variable_ty, llvariable_val| {
match pat_binding_mode {
ast::bind_infer => {
// By value binding: move the value that `val`
// points at into the binding's stack slot.
let datum = Datum {val: val,
ty: variable_ty,
mode: ByRef(ZeroMem)};
datum.store_to(bcx, INIT, llvariable_val)
}
ast::bind_by_ref(_) => {
// By ref binding: the value of the variable
// is the pointer `val` itself.
Store(bcx, val, llvariable_val);
bcx
}
}
});
}
for inner.iter().advance |inner_pat| {
bcx = bind_irrefutable_pat(
bcx, *inner_pat, val, true, binding_mode);
for inner.iter().advance |&inner_pat| {
bcx = bind_irrefutable_pat(bcx, inner_pat, val, binding_mode);
}
}
ast::pat_enum(_, ref sub_pats) => {
@ -1799,11 +1943,8 @@ pub fn bind_irrefutable_pat(bcx: block,
val);
for sub_pats.iter().advance |sub_pat| {
for args.vals.iter().enumerate().advance |(i, argval)| {
bcx = bind_irrefutable_pat(bcx,
sub_pat[i],
*argval,
make_copy,
binding_mode);
bcx = bind_irrefutable_pat(bcx, sub_pat[i],
*argval, binding_mode);
}
}
}
@ -1818,19 +1959,14 @@ pub fn bind_irrefutable_pat(bcx: block,
let repr = adt::represent_node(bcx, pat.id);
for elems.iter().enumerate().advance |(i, elem)| {
let fldptr = adt::trans_field_ptr(bcx, repr,
val, 0, i);
bcx = bind_irrefutable_pat(bcx,
*elem,
fldptr,
make_copy,
binding_mode);
val, 0, i);
bcx = bind_irrefutable_pat(bcx, *elem,
fldptr, binding_mode);
}
}
}
}
Some(&ast::def_static(_, false)) => {
bcx = bind_irrefutable_pat(bcx, pat, val, make_copy,
binding_mode);
}
_ => {
// Nothing to do here.
@ -1845,12 +1981,8 @@ pub fn bind_irrefutable_pat(bcx: block,
for fields.iter().advance |f| {
let ix = ty::field_idx_strict(tcx, f.ident, field_tys);
let fldptr = adt::trans_field_ptr(bcx, pat_repr, val,
discr, ix);
bcx = bind_irrefutable_pat(bcx,
f.pat,
fldptr,
make_copy,
binding_mode);
discr, ix);
bcx = bind_irrefutable_pat(bcx, f.pat, fldptr, binding_mode);
}
}
}
@ -1858,11 +1990,7 @@ pub fn bind_irrefutable_pat(bcx: block,
let repr = adt::represent_node(bcx, pat.id);
for elems.iter().enumerate().advance |(i, elem)| {
let fldptr = adt::trans_field_ptr(bcx, repr, val, 0, i);
bcx = bind_irrefutable_pat(bcx,
*elem,
fldptr,
make_copy,
binding_mode);
bcx = bind_irrefutable_pat(bcx, *elem, fldptr, binding_mode);
}
}
ast::pat_box(inner) | ast::pat_uniq(inner) => {
@ -1872,22 +2000,30 @@ pub fn bind_irrefutable_pat(bcx: block,
ty::ty_uniq(*) if !ty::type_contents(bcx.tcx(), pat_ty).contains_managed() => llbox,
_ => GEPi(bcx, llbox, [0u, abi::box_field_body])
};
bcx = bind_irrefutable_pat(bcx,
inner,
unboxed,
true,
binding_mode);
bcx = bind_irrefutable_pat(bcx, inner, unboxed, binding_mode);
}
ast::pat_region(inner) => {
let loaded_val = Load(bcx, val);
bcx = bind_irrefutable_pat(bcx,
inner,
loaded_val,
true,
binding_mode);
bcx = bind_irrefutable_pat(bcx, inner, loaded_val, binding_mode);
}
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) |
ast::pat_vec(*) => ()
ast::pat_vec(*) => {
bcx.tcx().sess.span_bug(
pat.span,
fmt!("vector patterns are never irrefutable!"));
}
ast::pat_wild | ast::pat_lit(_) | ast::pat_range(_, _) => ()
}
return bcx;
}
fn simple_identifier(pat: @ast::pat) -> Option<@ast::Path> {
match pat.node {
ast::pat_ident(ast::bind_infer, path, None) => {
Some(path)
}
_ => {
None
}
}
}

View File

@ -59,6 +59,7 @@ use middle::trans::type_of::*;
use middle::ty;
use util::common::indenter;
use util::ppaux::{Repr, ty_to_str};
use middle::pat_util;
use middle::trans::type_::Type;
@ -75,7 +76,7 @@ use extra::time;
use extra::sort;
use syntax::ast::ident;
use syntax::ast_map::{path, path_elt_to_str, path_name};
use syntax::ast_util::{local_def, path_to_ident};
use syntax::ast_util::{local_def};
use syntax::attr;
use syntax::codemap::span;
use syntax::parse::token;
@ -1121,9 +1122,6 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
let _indenter = indenter();
let _icx = push_ctxt("init_local");
let ty = node_id_type(bcx, local.node.id);
debug!("ty=%s", bcx.ty_to_str(ty));
if ignore_lhs(bcx, local) {
// Handle let _ = e; just like e;
@ -1135,36 +1133,7 @@ pub fn init_local(bcx: block, local: &ast::local) -> block {
}
}
let llptr = match bcx.fcx.lllocals.find_copy(&local.node.id) {
Some(v) => v,
_ => {
bcx.tcx().sess.span_bug(local.span,
"init_local: Someone forgot to document why it's\
safe to assume local.node.init must be local_mem!");
}
};
let mut bcx = bcx;
match local.node.init {
Some(init) => {
bcx = expr::trans_into(bcx, init, expr::SaveIn(llptr));
}
_ => {
zero_mem(bcx, llptr, ty);
}
}
// Make a note to drop this slot on the way out.
debug!("adding clean for %?/%s to bcx=%s",
local.node.id, bcx.ty_to_str(ty),
bcx.to_str());
add_clean(bcx, llptr, ty);
return _match::bind_irrefutable_pat(bcx,
local.node.pat,
llptr,
false,
_match::BindLocal);
_match::store_local(bcx, local.node.pat, local.node.init)
}
pub fn trans_stmt(cx: block, s: &ast::stmt) -> block {
@ -1469,6 +1438,7 @@ pub fn block_locals(b: &ast::blk, it: &fn(@ast::local)) {
}
}
<<<<<<< variant A
pub fn alloc_local(cx: block, local: &ast::local) -> block {
let _icx = push_ctxt("alloc_local");
let t = node_id_type(cx, local.node.id);
@ -1491,6 +1461,31 @@ pub fn alloc_local(cx: block, local: &ast::local) -> block {
}
>>>>>>> variant B
####### Ancestor
pub fn alloc_local(cx: block, local: @ast::local) -> block {
let _icx = push_ctxt("alloc_local");
let t = node_id_type(cx, local.node.id);
let simple_name = match local.node.pat.node {
ast::pat_ident(_, pth, None) => Some(path_to_ident(pth)),
_ => None
};
let val = alloc_ty(cx, t);
if cx.sess().opts.debuginfo {
for simple_name.iter().advance |name| {
str::as_c_str(cx.ccx().sess.str_of(*name), |buf| {
unsafe {
llvm::LLVMSetValueName(val, buf)
}
});
}
}
cx.fcx.lllocals.insert(local.node.id, val);
cx
}
======= end
pub fn with_cond(bcx: block, val: ValueRef, f: &fn(block) -> block) -> block {
let _icx = push_ctxt("with_cond");
let next_cx = base::sub_block(bcx, "next");
@ -1739,6 +1734,7 @@ pub fn create_llargs_for_fn_args(cx: fn_ctxt,
let arg = &args[i];
let llarg = llvm::LLVMGetParam(cx.llfn, arg_n as c_uint);
// FIXME #7260: aliasing should be determined by monomorphized ty::t
match arg.ty.node {
// `~` pointers never alias other parameters, because ownership was transferred
ast::ty_uniq(_) => {
@ -1783,7 +1779,6 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
for uint::range(0, arg_tys.len()) |arg_n| {
let arg_ty = arg_tys[arg_n];
let raw_llarg = raw_llargs[arg_n];
let arg_id = args[arg_n].id;
// For certain mode/type combinations, the raw llarg values are passed
// by value. However, within the fn body itself, we want to always
@ -1794,22 +1789,13 @@ pub fn copy_args_to_allocas(fcx: fn_ctxt,
// the event it's not truly needed.
// only by value if immediate:
let llarg = if datum::appropriate_mode(bcx.tcx(), arg_ty).is_by_value() {
let alloc = alloc_ty(bcx, arg_ty);
let alloc = alloc_ty(bcx, arg_ty, "__arg");
Store(bcx, raw_llarg, alloc);
alloc
} else {
raw_llarg
};
add_clean(bcx, llarg, arg_ty);
bcx = _match::bind_irrefutable_pat(bcx,
args[arg_n].pat,
llarg,
false,
_match::BindArgument);
fcx.llargs.insert(arg_id, llarg);
bcx = _match::store_arg(bcx, args[arg_n].pat, llarg);
if fcx.ccx.sess.opts.extra_debuginfo && fcx_has_nonzero_span(fcx) {
debuginfo::create_arg(bcx, &args[arg_n], args[arg_n].ty.span);
@ -1968,81 +1954,51 @@ pub fn trans_fn(ccx: @mut CrateContext,
|_bcx| { });
}
fn insert_synthetic_type_entries(bcx: block,
fn_args: &[ast::arg],
arg_tys: &[ty::t])
{
/*!
* For tuple-like structs and enum-variants, we generate
* synthetic AST nodes for the arguments. These have no types
* in the type table and no entries in the moves table,
* so the code in `copy_args_to_allocas` and `bind_irrefutable_pat`
* gets upset. This hack of a function bridges the gap by inserting types.
*
* This feels horrible. I think we should just have a special path
* for these functions and not try to use the generic code, but
* that's not the problem I'm trying to solve right now. - nmatsakis
*/
let tcx = bcx.tcx();
for uint::range(0, fn_args.len()) |i| {
debug!("setting type of argument %u (pat node %d) to %s",
i, fn_args[i].pat.id, bcx.ty_to_str(arg_tys[i]));
let pat_id = fn_args[i].pat.id;
let arg_ty = arg_tys[i];
tcx.node_types.insert(pat_id as uint, arg_ty);
}
}
pub fn trans_enum_variant(ccx: @mut CrateContext,
enum_id: ast::node_id,
_enum_id: ast::node_id,
variant: &ast::variant,
args: &[ast::variant_arg],
disr: int,
param_substs: Option<@param_substs>,
llfndecl: ValueRef) {
let _icx = push_ctxt("trans_enum_variant");
// Translate variant arguments to function arguments.
let fn_args = do args.map |varg| {
ast::arg {
is_mutbl: false,
ty: copy varg.ty,
pat: ast_util::ident_to_pat(
ccx.tcx.sess.next_node_id(),
codemap::dummy_sp(),
special_idents::arg),
id: varg.id,
}
};
let ty_param_substs = match param_substs {
Some(ref substs) => { copy substs.tys }
None => ~[]
};
let enum_ty = ty::subst_tps(ccx.tcx,
ty_param_substs,
None,
ty::node_id_to_type(ccx.tcx, enum_id));
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
variant.node.id,
enum_ty,
param_substs,
None);
let raw_llargs = create_llargs_for_fn_args(fcx, no_self, fn_args);
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, variant.node.id));
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
// XXX is there a better way to reconstruct the ty::t?
let repr = adt::represent_type(ccx, enum_ty);
debug!("trans_enum_variant: name=%s tps=%s repr=%? enum_ty=%s",
unsafe { str::raw::from_c_str(llvm::LLVMGetValueName(llfndecl)) },
~"[" + ty_param_substs.map(|&t| ty_to_str(ccx.tcx, t)).connect(", ") + "]",
repr, ty_to_str(ccx.tcx, enum_ty));
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
for args.iter().enumerate().advance |(i, va)| {
let lldestptr = adt::trans_field_ptr(bcx,
repr,
fcx.llretptr.get(),
disr,
i);
// If this argument to this function is a enum, it'll have come in to
// 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.
let llarg = match fcx.llargs.find(&va.id) {
Some(&x) => x,
_ => fail!("trans_enum_variant: how do we know this works?"),
};
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
build_return(bcx);
finish_fn(fcx, lltop);
trans_enum_variant_or_tuple_like_struct(
ccx,
variant.node.id,
args,
disr,
param_substs,
llfndecl);
}
// NB: In theory this should be merged with the function above. But the AST
// structures are completely different, so very little code would be shared.
pub fn trans_tuple_struct(ccx: @mut CrateContext,
fields: &[@ast::struct_field],
ctor_id: ast::node_id,
@ -2050,37 +2006,72 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
llfndecl: ValueRef) {
let _icx = push_ctxt("trans_tuple_struct");
// Translate struct fields to function arguments.
let fn_args = do fields.map |field| {
trans_enum_variant_or_tuple_like_struct(
ccx,
ctor_id,
fields,
0,
param_substs,
llfndecl);
}
trait IdAndTy {
fn id(&self) -> ast::node_id;
fn ty(&self) -> @ast::Ty;
}
impl IdAndTy for ast::variant_arg {
fn id(&self) -> ast::node_id { self.id }
fn ty(&self) -> @ast::Ty { self.ty }
}
impl IdAndTy for @ast::struct_field {
fn id(&self) -> ast::node_id { self.node.id }
fn ty(&self) -> @ast::Ty { self.node.ty }
}
pub fn trans_enum_variant_or_tuple_like_struct<A:IdAndTy>(
ccx: @mut CrateContext,
ctor_id: ast::node_id,
args: &[A],
disr: int,
param_substs: Option<@param_substs>,
llfndecl: ValueRef)
{
// Translate variant arguments to function arguments.
let fn_args = do args.map |varg| {
ast::arg {
is_mutbl: false,
ty: copy field.node.ty,
pat: ast_util::ident_to_pat(ccx.tcx.sess.next_node_id(),
codemap::dummy_sp(),
special_idents::arg),
id: field.node.id
ty: varg.ty(),
pat: ast_util::ident_to_pat(
ccx.tcx.sess.next_node_id(),
codemap::dummy_sp(),
special_idents::arg),
id: varg.id(),
}
};
// XXX is there a better way to reconstruct the ty::t?
let ty_param_substs = match param_substs {
Some(ref substs) => { copy substs.tys }
None => ~[]
};
let ctor_ty = ty::subst_tps(ccx.tcx, ty_param_substs, None,
ty::node_id_to_type(ccx.tcx, ctor_id));
let tup_ty = match ty::get(ctor_ty).sty {
let result_ty = match ty::get(ctor_ty).sty {
ty::ty_bare_fn(ref bft) => bft.sig.output,
_ => ccx.sess.bug(fmt!("trans_tuple_struct: unexpected ctor \
return type %s",
ty_to_str(ccx.tcx, ctor_ty)))
_ => ccx.sess.bug(
fmt!("trans_enum_variant_or_tuple_like_struct: \
unexpected ctor return type %s",
ty_to_str(ccx.tcx, ctor_ty)))
};
let fcx = new_fn_ctxt_w_id(ccx,
~[],
llfndecl,
ctor_id,
tup_ty,
result_ty,
param_substs,
None);
@ -2088,23 +2079,23 @@ pub fn trans_tuple_struct(ccx: @mut CrateContext,
let bcx = top_scope_block(fcx, None);
let lltop = bcx.llbb;
let arg_tys = ty::ty_fn_args(node_id_type(bcx, ctor_id));
let arg_tys = ty::ty_fn_args(ctor_ty);
insert_synthetic_type_entries(bcx, fn_args, arg_tys);
let bcx = copy_args_to_allocas(fcx, bcx, fn_args, raw_llargs, arg_tys);
let repr = adt::represent_type(ccx, tup_ty);
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), 0);
for fields.iter().enumerate().advance |(i, field)| {
let repr = adt::represent_type(ccx, result_ty);
adt::trans_start_init(bcx, repr, fcx.llretptr.get(), disr);
for fn_args.iter().enumerate().advance |(i, fn_arg)| {
let lldestptr = adt::trans_field_ptr(bcx,
repr,
fcx.llretptr.get(),
0,
disr,
i);
let llarg = fcx.llargs.get_copy(&field.node.id);
let llarg = fcx.llargs.get_copy(&fn_arg.pat.id);
let arg_ty = arg_tys[i];
memcpy_ty(bcx, lldestptr, llarg, arg_ty);
}
build_return(bcx);
finish_fn(fcx, lltop);
}
@ -3039,8 +3030,8 @@ pub fn trans_crate(sess: session::Session,
}
}
if ccx.sess.count_llvm_insns() {
for ccx.stats.llvm_insns.iter().advance |(&k, &v)| {
io::println(fmt!("%-7u %s", v, k));
for ccx.stats.llvm_insns.each |k, v| {
io::println(fmt!("%-7u %s", *v, *k));
}
}

View File

@ -860,8 +860,6 @@ pub fn trans_arg_expr(bcx: block,
// FIXME(#3548) use the adjustments table
match autoref_arg {
DoAutorefArg => {
assert!(!
bcx.ccx().maps.moves_map.contains(&arg_expr.id));
val = arg_datum.to_ref_llval(bcx);
}
DontAutorefArg => {

View File

@ -35,9 +35,6 @@ use syntax::codemap::span;
pub fn trans_block(bcx: block, b: &ast::blk, dest: expr::Dest) -> block {
let _icx = push_ctxt("trans_block");
let mut bcx = bcx;
do block_locals(b) |local| {
bcx = alloc_local(bcx, local);
};
for b.node.stmts.iter().advance |s| {
debuginfo::update_source_pos(bcx, b.span);
bcx = trans_stmt(bcx, *s);

View File

@ -70,8 +70,8 @@
* This is a "shallow" clone. After `move_to()`, the current datum
* is invalid and should no longer be used.
*
* - `store_to()` either performs a copy or a move by consulting the
* moves_map computed by `middle::moves`.
* - `store_to()` either performs a copy or a move depending on the
* Rust type of the datum.
*
* # Scratch datum
*
@ -208,7 +208,6 @@ pub fn appropriate_mode(tcx: ty::ctxt, ty: ty::t) -> DatumMode {
impl Datum {
pub fn store_to(&self,
bcx: block,
id: ast::node_id,
action: CopyAction,
dst: ValueRef)
-> block {
@ -218,7 +217,7 @@ impl Datum {
* `id` is located in the move table, but copies otherwise.
*/
if bcx.ccx().maps.moves_map.contains(&id) {
if ty::type_moves_by_default(bcx.tcx(), self.ty) {
self.move_to(bcx, action, dst)
} else {
self.copy_to(bcx, action, dst)
@ -227,7 +226,6 @@ impl Datum {
pub fn store_to_dest(&self,
bcx: block,
id: ast::node_id,
dest: expr::Dest)
-> block {
match dest {
@ -235,21 +233,20 @@ impl Datum {
return bcx;
}
expr::SaveIn(addr) => {
return self.store_to(bcx, id, INIT, addr);
return self.store_to(bcx, INIT, addr);
}
}
}
pub fn store_to_datum(&self,
bcx: block,
id: ast::node_id,
action: CopyAction,
datum: Datum)
-> block {
debug!("store_to_datum(self=%s, action=%?, datum=%s)",
self.to_str(bcx.ccx()), action, datum.to_str(bcx.ccx()));
assert!(datum.mode.is_by_ref());
self.store_to(bcx, id, action, datum.val)
self.store_to(bcx, action, datum.val)
}
pub fn move_to_datum(&self, bcx: block, action: CopyAction, datum: Datum)
@ -828,11 +825,10 @@ impl DatumBlock {
}
pub fn store_to(&self,
id: ast::node_id,
action: CopyAction,
dst: ValueRef)
-> block {
self.datum.store_to(self.bcx, id, action, dst)
self.datum.store_to(self.bcx, action, dst)
}
pub fn copy_to(&self, action: CopyAction, dst: ValueRef) -> block {

View File

@ -23,7 +23,8 @@ This will generate code that evaluates `expr`, storing the result into
`Dest`, which must either be the special flag ignore (throw the result
away) or be a pointer to memory of the same type/size as the
expression. It returns the resulting basic block. This form will
handle all automatic adjustments and moves for you.
handle all automatic adjustments for you. The value will be moved if
its type is linear and copied otherwise.
## Translation to a datum
@ -42,18 +43,18 @@ This function generates code to evaluate the expression and return a
tries to return its result in the most efficient way possible, without
introducing extra copies or sacrificing information. Therefore, for
lvalue expressions, you always get a by-ref `Datum` in return that
points at the memory for this lvalue (almost, see [1]). For rvalue
expressions, we will return a by-value `Datum` whenever possible, but
it is often necessary to allocate a stack slot, store the result of
the rvalue in there, and then return a pointer to the slot (see the
discussion later on about the different kinds of rvalues).
points at the memory for this lvalue. For rvalue expressions, we will
return a by-value `Datum` whenever possible, but it is often necessary
to allocate a stack slot, store the result of the rvalue in there, and
then return a pointer to the slot (see the discussion later on about
the different kinds of rvalues).
NB: The `trans_to_datum()` function does perform adjustments, but
since it returns a pointer to the value "in place" it does not handle
any moves that may be relevant. If you are transing an expression
whose result should be moved, you should either use the Datum methods
`move_to()` (for unconditional moves) or `store_to()` (for moves
conditioned on the type of the expression) at some point.
moves. If you wish to copy/move the value returned into a new
location, you should use the Datum method `store_to()` (move or copy
depending on type). You can also use `move_to()` (force move) or
`copy_to()` (force copy) for special situations.
## Translating local variables
@ -110,13 +111,6 @@ generate phi nodes).
Finally, statement rvalues are rvalues that always produce a nil
return type, such as `while` loops or assignments (`a = b`).
## Caveats
[1] Actually, some lvalues are only stored by value and not by
reference. An example (as of this writing) would be immutable
arguments or pattern bindings of immediate type. However, mutable
lvalues are *never* stored by value.
*/
@ -315,7 +309,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
let datumblock = trans_to_datum(bcx, expr);
return match dest {
Ignore => datumblock.bcx,
SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
SaveIn(lldest) => datumblock.store_to(INIT, lldest)
};
}
@ -343,7 +337,7 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
let datumblock = trans_lvalue_unadjusted(bcx, expr);
match dest {
Ignore => datumblock.bcx,
SaveIn(lldest) => datumblock.store_to(expr.id, INIT, lldest)
SaveIn(lldest) => datumblock.store_to(INIT, lldest)
}
}
ty::RvalueDatumExpr => {
@ -351,8 +345,9 @@ pub fn trans_into(bcx: block, expr: @ast::expr, dest: Dest) -> block {
match dest {
Ignore => datumblock.drop_val(),
// NB: We always do `move_to()` regardless of the
// moves_map because we're processing an rvalue
// When processing an rvalue, the value will be newly
// allocated, so we always `move_to` so as not to
// unnecessarily inc ref counts and so forth:
SaveIn(lldest) => datumblock.move_to(INIT, lldest)
}
}
@ -386,11 +381,11 @@ fn trans_lvalue(bcx: block, expr: @ast::expr) -> DatumBlock {
fn trans_to_datum_unadjusted(bcx: block, expr: @ast::expr) -> DatumBlock {
/*!
*
* Translates an expression into a datum. If this expression
* is an rvalue, this will result in a temporary value being
* created. If you already know where the result should be stored,
* you should use `trans_into()` instead. */
* created. If you plan to store the value somewhere else,
* you should prefer `trans_into()` instead.
*/
let mut bcx = bcx;
@ -535,7 +530,7 @@ fn trans_rvalue_stmt_unadjusted(bcx: block, expr: @ast::expr) -> block {
let dst_datum = unpack_datum!(
bcx, trans_lvalue(bcx, dst));
return src_datum.store_to_datum(
bcx, src.id, DROP_EXISTING, dst_datum);
bcx, DROP_EXISTING, dst_datum);
}
ast::expr_assign_op(callee_id, op, dst, src) => {
return trans_assign_op(bcx, expr, callee_id, op, dst, src);
@ -638,7 +633,15 @@ fn trans_rvalue_dps_unadjusted(bcx: block, expr: @ast::expr,
return trans_into(bcx, blk, dest);
}
ast::expr_copy(a) => {
return trans_into(bcx, a, dest);
// If we just called `trans_into(bcx, a, dest)`, then this
// might *move* the value into `dest` if the value is
// non-copyable. So first get a datum and then do an
// explicit copy.
let datumblk = trans_to_datum(bcx, a);
return match dest {
Ignore => datumblk.bcx,
SaveIn(llval) => datumblk.copy_to(INIT, llval)
};
}
ast::expr_call(f, ref args, _) => {
return callee::trans_call(
@ -1221,6 +1224,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
bcx = trans_into(bcx, e, Ignore);
}
for optbase.iter().advance |sbi| {
// FIXME #7261: this moves entire base, not just certain fields
bcx = trans_into(bcx, sbi.expr, Ignore);
}
return bcx;
@ -1245,7 +1249,7 @@ fn trans_adt(bcx: block, repr: &adt::Repr, discr: int,
adt::trans_field_ptr(bcx, repr, srcval, discr, i)
};
let dest = adt::trans_field_ptr(bcx, repr, addr, discr, i);
bcx = datum.store_to(bcx, base.expr.id, INIT, dest);
bcx = datum.store_to(bcx, INIT, dest);
}
}