Skip to content

Commit

Permalink
Extend trans::datum::Lvalue so that it carrys an optional dropflag …
Browse files Browse the repository at this point in the history
…hint.

Instrumented calls sites that construct Lvalues to ease tracking down
cases that we might need to change whether or not they carry a hint.

Note that this commit does not do anything to actually *construct*
the `lldropflag_hints` map, nor does it change anything about codegen
itself. Those parts are in follow-on commits.
  • Loading branch information
pnkfelix committed Jul 28, 2015
1 parent 20aa27b commit a0f3f2a
Show file tree
Hide file tree
Showing 7 changed files with 213 additions and 31 deletions.
32 changes: 24 additions & 8 deletions src/librustc_trans/trans/_match.rs
Original file line number Diff line number Diff line change
Expand Up @@ -437,7 +437,7 @@ impl MatchInput {
fn from_val(val: ValueRef) -> MatchInput {
MatchInput {
val: val,
lval: Lvalue,
lval: Lvalue::new("MatchInput::from_val"),
}
}

Expand Down Expand Up @@ -941,30 +941,41 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
cs: Option<cleanup::ScopeId>)
-> Block<'blk, 'tcx> {
for (&ident, &binding_info) in bindings_map {
let llval = match binding_info.trmode {
let (llval, aliases_other_state) = match binding_info.trmode {
// By value mut binding for a copy type: load from the ptr
// into the matched value and copy to our alloca
TrByCopy(llbinding) |
TrByMoveIntoCopy(llbinding) => {
let llval = Load(bcx, binding_info.llmatch);
let datum = Datum::new(llval, binding_info.ty, Lvalue);
let lval = match binding_info.trmode {
TrByCopy(..) =>
Lvalue::new("_match::insert_lllocals"),
TrByMoveIntoCopy(..) =>
Lvalue::match_input("_match::insert_lllocals", bcx, binding_info.id),
_ => unreachable!(),
};
let datum = Datum::new(llval, binding_info.ty, lval);
call_lifetime_start(bcx, llbinding);
bcx = datum.store_to(bcx, llbinding);
if let Some(cs) = cs {
bcx.fcx.schedule_lifetime_end(cs, llbinding);
}

llbinding
(llbinding, false)
},

// By value move bindings: load from the ptr into the matched value
TrByMoveRef => Load(bcx, binding_info.llmatch),
TrByMoveRef => (Load(bcx, binding_info.llmatch), true),

// By ref binding: use the ptr into the matched value
TrByRef => binding_info.llmatch
TrByRef => (binding_info.llmatch, true),
};

let datum = Datum::new(llval, binding_info.ty, Lvalue);
let lval = Lvalue::local("_match::insert_lllocals",
bcx,
binding_info.id,
aliases_other_state);
let datum = Datum::new(llval, binding_info.ty, lval);
if let Some(cs) = cs {
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty);
Expand Down Expand Up @@ -1619,6 +1630,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let scope = cleanup::var_scope(tcx, p_id);
bcx = mk_binding_alloca(
bcx, p_id, path1.node.name, scope, (),
"_match::store_local::create_dummy_locals",
|(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx });
});
bcx
Expand All @@ -1641,6 +1653,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
let var_scope = cleanup::var_scope(tcx, local.id);
return mk_binding_alloca(
bcx, pat.id, ident.name, var_scope, (),
"_match::store_local",
|(), bcx, v, _| expr::trans_into(bcx, &**init_expr,
expr::SaveIn(v)));
}
Expand Down Expand Up @@ -1668,6 +1681,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
name: ast::Name,
cleanup_scope: cleanup::ScopeId,
arg: A,
caller_name: &'static str,
populate: F)
-> Block<'blk, 'tcx> where
F: FnOnce(A, Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
Expand All @@ -1685,7 +1699,8 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,

// Now that memory is initialized and has cleanup scheduled,
// create the datum and insert into the local variable map.
let datum = Datum::new(llval, var_ty, Lvalue);
let lval = Lvalue::binding(caller_name, bcx, p_id, name);
let datum = Datum::new(llval, var_ty, lval);
bcx.fcx.lllocals.borrow_mut().insert(p_id, datum);
bcx
}
Expand Down Expand Up @@ -1730,6 +1745,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
// map.
bcx = mk_binding_alloca(
bcx, pat.id, path1.node.name, cleanup_scope, (),
"_match::bind_irrefutable_pat",
|(), bcx, llval, ty| {
match pat_binding_mode {
ast::BindByValue(_) => {
Expand Down
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/adt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1083,7 +1083,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
));
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
datum::Datum::new(ptr, ptr_ty, datum::Lvalue)
datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr"))
.store_to(variant_cx, scratch.val)
});
let expr_datum = scratch.to_expr_datum();
Expand Down
3 changes: 2 additions & 1 deletion src/librustc_trans/trans/base.rs
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ use trans::cleanup;
use trans::closure;
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
use trans::common::{CrateContext, FunctionContext};
use trans::common::{CrateContext, DropFlagHintsMap, FunctionContext};
use trans::common::{Result, NodeIdAndSpan};
use trans::common::{node_id_type, return_type_is_void};
use trans::common::{type_is_immediate, type_is_zero_size, val_ty};
Expand Down Expand Up @@ -1235,6 +1235,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
caller_expects_out_pointer: uses_outptr,
lllocals: RefCell::new(NodeMap()),
llupvars: RefCell::new(NodeMap()),
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
id: id,
param_substs: param_substs,
span: sp,
Expand Down
7 changes: 7 additions & 0 deletions src/librustc_trans/trans/cleanup.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,7 @@ use trans::base;
use trans::build;
use trans::common;
use trans::common::{Block, FunctionContext, NodeIdAndSpan};
use trans::datum::{Datum, Lvalue};
use trans::debuginfo::{DebugLoc, ToDebugLoc};
use trans::glue;
use middle::region;
Expand Down Expand Up @@ -212,6 +213,12 @@ pub enum ScopeId {
CustomScope(CustomScopeIndex)
}

#[derive(Copy, Clone, Debug)]
pub struct DropHint<K>(pub ast::NodeId, pub K);

pub type DropHintDatum<'tcx> = DropHint<Datum<'tcx, Lvalue>>;
pub type DropHintValue = DropHint<ValueRef>;

impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
/// Invoked when we start to trans the code contained within a new cleanup scope.
fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) {
Expand Down
25 changes: 25 additions & 0 deletions src/librustc_trans/trans/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,27 @@ pub fn validate_substs(substs: &Substs) {
type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;

#[derive(Clone, Debug)]
struct HintEntry<'tcx> {
// The datum for the dropflag-hint itself; note that many
// source-level Lvalues will be associated with the same
// dropflag-hint datum.
datum: cleanup::DropHintDatum<'tcx>,
}

pub struct DropFlagHintsMap<'tcx> {
// Maps NodeId for expressions that read/write unfragmented state
// to that state's drop-flag "hint." (A stack-local hint
// indicates either that (1.) it is certain that no-drop is
// needed, or (2.) inline drop-flag must be consulted.)
node_map: NodeMap<HintEntry<'tcx>>,
}

impl<'tcx> DropFlagHintsMap<'tcx> {
pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } }
pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) }
}

// Function context. Every LLVM function we create will have one of
// these.
pub struct FunctionContext<'a, 'tcx: 'a> {
Expand Down Expand Up @@ -349,6 +370,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
// Same as above, but for closure upvars
pub llupvars: RefCell<NodeMap<ValueRef>>,

// Carries info about drop-flags for local bindings (longer term,
// paths) for the code being compiled.
pub lldropflag_hints: RefCell<DropFlagHintsMap<'tcx>>,

// The NodeId of the function, or -1 if it doesn't correspond to
// a user-defined function.
pub id: ast::NodeId,
Expand Down
147 changes: 137 additions & 10 deletions src/librustc_trans/trans/datum.rs
Original file line number Diff line number Diff line change
Expand Up @@ -138,17 +138,141 @@ pub enum Expr {
/// `val` is a pointer into memory for which a cleanup is scheduled
/// (and thus has type *T). If you move out of an Lvalue, you must
/// zero out the memory (FIXME #5016).
LvalueExpr,
LvalueExpr(Lvalue),
}

#[derive(Clone, Copy, Debug)]
pub struct Lvalue;
#[derive(Copy, Clone, Debug)]
pub enum DropFlagInfo {
DontZeroJustUse(ast::NodeId),
ZeroAndMaintain(ast::NodeId),
None,
}

impl DropFlagInfo {
pub fn must_zero(&self) -> bool {
match *self {
DropFlagInfo::DontZeroJustUse(..) => false,
DropFlagInfo::ZeroAndMaintain(..) => true,
DropFlagInfo::None => true,
}
}

pub fn hint_to_maintain(&self) -> Option<ast::NodeId> {
match *self {
DropFlagInfo::DontZeroJustUse(id) => Some(id),
DropFlagInfo::ZeroAndMaintain(id) => Some(id),
DropFlagInfo::None => None,
}
}
}

// FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients
// may not realize that subparts of an Lvalue can have a subset of
// drop-flags associated with them, while this as written will just
// memcpy the drop_flag_info. But, it is an easier way to get `_match`
// off the ground to just let this be `Copy` for now.
#[derive(Copy, Clone, Debug)]
pub struct Lvalue {
pub source: &'static str,
pub drop_flag_info: DropFlagInfo
}

#[derive(Debug)]
pub struct Rvalue {
pub mode: RvalueMode
}

impl Lvalue {
pub fn new(source: &'static str) -> Lvalue {
Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
}

pub fn upvar<'blk, 'tcx>(source: &'static str,
bcx: Block<'blk, 'tcx>,
id: ast::NodeId) -> Lvalue {
let info = if Lvalue::has_dropflag_hint(bcx, id) {
DropFlagInfo::ZeroAndMaintain(id)
} else {
DropFlagInfo::None
};
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
debug!("upvar Lvalue at {}, id: {} info: {:?}", source, id, info);
Lvalue { source: source, drop_flag_info: info }
}

pub fn match_input<'blk, 'tcx>(source: &'static str,
bcx: Block<'blk, 'tcx>,
id: ast::NodeId) -> Lvalue
{
let info = if Lvalue::has_dropflag_hint(bcx, id) {
// match_input is used to move from the input into a
// separate stack slot; it must zero (at least until we
// improve things to track drop flags for the fragmented
// parent match input expression).
DropFlagInfo::ZeroAndMaintain(id)
} else {
DropFlagInfo::None
};
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
debug!("match_input Lvalue at {}, id: {} info: {:?}", source, id, info);
Lvalue { source: source, drop_flag_info: info }
}

pub fn local<'blk, 'tcx>(source: &'static str,
bcx: Block<'blk, 'tcx>,
id: ast::NodeId,
aliases_other_state: bool)
-> Lvalue
{
let info = if Lvalue::has_dropflag_hint(bcx, id) {
if aliases_other_state {
DropFlagInfo::ZeroAndMaintain(id)
} else {
DropFlagInfo::DontZeroJustUse(id)
}
} else {
DropFlagInfo::None
};
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
debug!("local Lvalue at {}, id: {} info: {:?}", source, id, info);
Lvalue { source: source, drop_flag_info: info }
}

pub fn store_arg<'blk, 'tcx>(source: &'static str,
bcx: Block<'blk, 'tcx>,
id: ast::NodeId) -> Lvalue
{
let info = if Lvalue::has_dropflag_hint(bcx, id) {
DropFlagInfo::ZeroAndMaintain(id)
} else {
DropFlagInfo::None
};
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
debug!("store_arg Lvalue at {}, id: {} info: {:?}", source, id, info);
Lvalue { source: source, drop_flag_info: info }
}

pub fn binding<'blk, 'tcx>(source: &'static str,
bcx: Block<'blk, 'tcx>,
id: ast::NodeId,
name: ast::Name) -> Lvalue {
let info = if Lvalue::has_dropflag_hint(bcx, id) {
DropFlagInfo::DontZeroJustUse(id)
} else {
DropFlagInfo::None
};
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
debug!("binding Lvalue at {}, id: {} name: {} info: {:?}",
source, id, name, info);
Lvalue { source: source, drop_flag_info: info }
}

fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
id: ast::NodeId) -> bool {
bcx.fcx.lldropflag_hints.borrow().has_hint(id)
}
}

impl Rvalue {
pub fn new(m: RvalueMode) -> Rvalue {
Rvalue { mode: m }
Expand Down Expand Up @@ -201,7 +325,7 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
bcx.fcx.schedule_lifetime_end(scope, scratch);
bcx.fcx.schedule_drop_mem(scope, scratch, ty);

DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
}

/// Allocates temporary space on the stack using alloca() and returns a by-ref Datum pointing to
Expand Down Expand Up @@ -308,7 +432,7 @@ impl KindOps for Lvalue {
}

fn to_expr_kind(self) -> Expr {
LvalueExpr
LvalueExpr(self)
}
}

Expand All @@ -319,14 +443,14 @@ impl KindOps for Expr {
ty: Ty<'tcx>)
-> Block<'blk, 'tcx> {
match *self {
LvalueExpr => Lvalue.post_store(bcx, val, ty),
LvalueExpr(ref l) => l.post_store(bcx, val, ty),
RvalueExpr(ref r) => r.post_store(bcx, val, ty),
}
}

fn is_by_ref(&self) -> bool {
match *self {
LvalueExpr => Lvalue.is_by_ref(),
LvalueExpr(ref l) => l.is_by_ref(),
RvalueExpr(ref r) => r.is_by_ref()
}
}
Expand Down Expand Up @@ -360,7 +484,10 @@ impl<'tcx> Datum<'tcx, Rvalue> {
match self.kind.mode {
ByRef => {
add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue))
DatumBlock::new(bcx, Datum::new(
self.val,
self.ty,
Lvalue::new("datum::to_lvalue_datum_in_scope")))
}

ByValue => {
Expand Down Expand Up @@ -417,7 +544,7 @@ impl<'tcx> Datum<'tcx, Expr> {
{
let Datum { val, ty, kind } = self;
match kind {
LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)),
LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)),
RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
}
}
Expand Down Expand Up @@ -528,7 +655,7 @@ impl<'tcx> Datum<'tcx, Lvalue> {
};
Datum {
val: val,
kind: Lvalue,
kind: Lvalue::new("Datum::get_element"),
ty: ty,
}
}
Expand Down
Loading

0 comments on commit a0f3f2a

Please sign in to comment.