Skip to content

Commit a0f3f2a

Browse files
committed
Extend trans::datum::Lvalue so that it carrys an optional dropflag 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.
1 parent 20aa27b commit a0f3f2a

File tree

7 files changed

+213
-31
lines changed

7 files changed

+213
-31
lines changed

src/librustc_trans/trans/_match.rs

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -437,7 +437,7 @@ impl MatchInput {
437437
fn from_val(val: ValueRef) -> MatchInput {
438438
MatchInput {
439439
val: val,
440-
lval: Lvalue,
440+
lval: Lvalue::new("MatchInput::from_val"),
441441
}
442442
}
443443

@@ -941,30 +941,41 @@ fn insert_lllocals<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
941941
cs: Option<cleanup::ScopeId>)
942942
-> Block<'blk, 'tcx> {
943943
for (&ident, &binding_info) in bindings_map {
944-
let llval = match binding_info.trmode {
944+
let (llval, aliases_other_state) = match binding_info.trmode {
945945
// By value mut binding for a copy type: load from the ptr
946946
// into the matched value and copy to our alloca
947947
TrByCopy(llbinding) |
948948
TrByMoveIntoCopy(llbinding) => {
949949
let llval = Load(bcx, binding_info.llmatch);
950-
let datum = Datum::new(llval, binding_info.ty, Lvalue);
950+
let lval = match binding_info.trmode {
951+
TrByCopy(..) =>
952+
Lvalue::new("_match::insert_lllocals"),
953+
TrByMoveIntoCopy(..) =>
954+
Lvalue::match_input("_match::insert_lllocals", bcx, binding_info.id),
955+
_ => unreachable!(),
956+
};
957+
let datum = Datum::new(llval, binding_info.ty, lval);
951958
call_lifetime_start(bcx, llbinding);
952959
bcx = datum.store_to(bcx, llbinding);
953960
if let Some(cs) = cs {
954961
bcx.fcx.schedule_lifetime_end(cs, llbinding);
955962
}
956963

957-
llbinding
964+
(llbinding, false)
958965
},
959966

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

963970
// By ref binding: use the ptr into the matched value
964-
TrByRef => binding_info.llmatch
971+
TrByRef => (binding_info.llmatch, true),
965972
};
966973

967-
let datum = Datum::new(llval, binding_info.ty, Lvalue);
974+
let lval = Lvalue::local("_match::insert_lllocals",
975+
bcx,
976+
binding_info.id,
977+
aliases_other_state);
978+
let datum = Datum::new(llval, binding_info.ty, lval);
968979
if let Some(cs) = cs {
969980
bcx.fcx.schedule_lifetime_end(cs, binding_info.llmatch);
970981
bcx.fcx.schedule_drop_and_fill_mem(cs, llval, binding_info.ty);
@@ -1619,6 +1630,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16191630
let scope = cleanup::var_scope(tcx, p_id);
16201631
bcx = mk_binding_alloca(
16211632
bcx, p_id, path1.node.name, scope, (),
1633+
"_match::store_local::create_dummy_locals",
16221634
|(), bcx, llval, ty| { drop_done_fill_mem(bcx, llval, ty); bcx });
16231635
});
16241636
bcx
@@ -1641,6 +1653,7 @@ pub fn store_local<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
16411653
let var_scope = cleanup::var_scope(tcx, local.id);
16421654
return mk_binding_alloca(
16431655
bcx, pat.id, ident.name, var_scope, (),
1656+
"_match::store_local",
16441657
|(), bcx, v, _| expr::trans_into(bcx, &**init_expr,
16451658
expr::SaveIn(v)));
16461659
}
@@ -1668,6 +1681,7 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
16681681
name: ast::Name,
16691682
cleanup_scope: cleanup::ScopeId,
16701683
arg: A,
1684+
caller_name: &'static str,
16711685
populate: F)
16721686
-> Block<'blk, 'tcx> where
16731687
F: FnOnce(A, Block<'blk, 'tcx>, ValueRef, Ty<'tcx>) -> Block<'blk, 'tcx>,
@@ -1685,7 +1699,8 @@ fn mk_binding_alloca<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
16851699

16861700
// Now that memory is initialized and has cleanup scheduled,
16871701
// create the datum and insert into the local variable map.
1688-
let datum = Datum::new(llval, var_ty, Lvalue);
1702+
let lval = Lvalue::binding(caller_name, bcx, p_id, name);
1703+
let datum = Datum::new(llval, var_ty, lval);
16891704
bcx.fcx.lllocals.borrow_mut().insert(p_id, datum);
16901705
bcx
16911706
}
@@ -1730,6 +1745,7 @@ pub fn bind_irrefutable_pat<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
17301745
// map.
17311746
bcx = mk_binding_alloca(
17321747
bcx, pat.id, path1.node.name, cleanup_scope, (),
1748+
"_match::bind_irrefutable_pat",
17331749
|(), bcx, llval, ty| {
17341750
match pat_binding_mode {
17351751
ast::BindByValue(_) => {

src/librustc_trans/trans/adt.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1083,7 +1083,7 @@ pub fn trans_drop_flag_ptr<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
10831083
));
10841084
bcx = fold_variants(bcx, r, val, |variant_cx, st, value| {
10851085
let ptr = struct_field_ptr(variant_cx, st, value, (st.fields.len() - 1), false);
1086-
datum::Datum::new(ptr, ptr_ty, datum::Lvalue)
1086+
datum::Datum::new(ptr, ptr_ty, datum::Lvalue::new("adt::trans_drop_flag_ptr"))
10871087
.store_to(variant_cx, scratch.val)
10881088
});
10891089
let expr_datum = scratch.to_expr_datum();

src/librustc_trans/trans/base.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ use trans::cleanup;
5656
use trans::closure;
5757
use trans::common::{Block, C_bool, C_bytes_in_context, C_i32, C_int, C_integral};
5858
use trans::common::{C_null, C_struct_in_context, C_u64, C_u8, C_undef};
59-
use trans::common::{CrateContext, FunctionContext};
59+
use trans::common::{CrateContext, DropFlagHintsMap, FunctionContext};
6060
use trans::common::{Result, NodeIdAndSpan};
6161
use trans::common::{node_id_type, return_type_is_void};
6262
use trans::common::{type_is_immediate, type_is_zero_size, val_ty};
@@ -1235,6 +1235,7 @@ pub fn new_fn_ctxt<'a, 'tcx>(ccx: &'a CrateContext<'a, 'tcx>,
12351235
caller_expects_out_pointer: uses_outptr,
12361236
lllocals: RefCell::new(NodeMap()),
12371237
llupvars: RefCell::new(NodeMap()),
1238+
lldropflag_hints: RefCell::new(DropFlagHintsMap::new()),
12381239
id: id,
12391240
param_substs: param_substs,
12401241
span: sp,

src/librustc_trans/trans/cleanup.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -124,6 +124,7 @@ use trans::base;
124124
use trans::build;
125125
use trans::common;
126126
use trans::common::{Block, FunctionContext, NodeIdAndSpan};
127+
use trans::datum::{Datum, Lvalue};
127128
use trans::debuginfo::{DebugLoc, ToDebugLoc};
128129
use trans::glue;
129130
use middle::region;
@@ -212,6 +213,12 @@ pub enum ScopeId {
212213
CustomScope(CustomScopeIndex)
213214
}
214215

216+
#[derive(Copy, Clone, Debug)]
217+
pub struct DropHint<K>(pub ast::NodeId, pub K);
218+
219+
pub type DropHintDatum<'tcx> = DropHint<Datum<'tcx, Lvalue>>;
220+
pub type DropHintValue = DropHint<ValueRef>;
221+
215222
impl<'blk, 'tcx> CleanupMethods<'blk, 'tcx> for FunctionContext<'blk, 'tcx> {
216223
/// Invoked when we start to trans the code contained within a new cleanup scope.
217224
fn push_ast_cleanup_scope(&self, debug_loc: NodeIdAndSpan) {

src/librustc_trans/trans/common.rs

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -299,6 +299,27 @@ pub fn validate_substs(substs: &Substs) {
299299
type RvalueDatum<'tcx> = datum::Datum<'tcx, datum::Rvalue>;
300300
pub type LvalueDatum<'tcx> = datum::Datum<'tcx, datum::Lvalue>;
301301

302+
#[derive(Clone, Debug)]
303+
struct HintEntry<'tcx> {
304+
// The datum for the dropflag-hint itself; note that many
305+
// source-level Lvalues will be associated with the same
306+
// dropflag-hint datum.
307+
datum: cleanup::DropHintDatum<'tcx>,
308+
}
309+
310+
pub struct DropFlagHintsMap<'tcx> {
311+
// Maps NodeId for expressions that read/write unfragmented state
312+
// to that state's drop-flag "hint." (A stack-local hint
313+
// indicates either that (1.) it is certain that no-drop is
314+
// needed, or (2.) inline drop-flag must be consulted.)
315+
node_map: NodeMap<HintEntry<'tcx>>,
316+
}
317+
318+
impl<'tcx> DropFlagHintsMap<'tcx> {
319+
pub fn new() -> DropFlagHintsMap<'tcx> { DropFlagHintsMap { node_map: NodeMap() } }
320+
pub fn has_hint(&self, id: ast::NodeId) -> bool { self.node_map.contains_key(&id) }
321+
}
322+
302323
// Function context. Every LLVM function we create will have one of
303324
// these.
304325
pub struct FunctionContext<'a, 'tcx: 'a> {
@@ -349,6 +370,10 @@ pub struct FunctionContext<'a, 'tcx: 'a> {
349370
// Same as above, but for closure upvars
350371
pub llupvars: RefCell<NodeMap<ValueRef>>,
351372

373+
// Carries info about drop-flags for local bindings (longer term,
374+
// paths) for the code being compiled.
375+
pub lldropflag_hints: RefCell<DropFlagHintsMap<'tcx>>,
376+
352377
// The NodeId of the function, or -1 if it doesn't correspond to
353378
// a user-defined function.
354379
pub id: ast::NodeId,

src/librustc_trans/trans/datum.rs

Lines changed: 137 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -138,17 +138,141 @@ pub enum Expr {
138138
/// `val` is a pointer into memory for which a cleanup is scheduled
139139
/// (and thus has type *T). If you move out of an Lvalue, you must
140140
/// zero out the memory (FIXME #5016).
141-
LvalueExpr,
141+
LvalueExpr(Lvalue),
142142
}
143143

144-
#[derive(Clone, Copy, Debug)]
145-
pub struct Lvalue;
144+
#[derive(Copy, Clone, Debug)]
145+
pub enum DropFlagInfo {
146+
DontZeroJustUse(ast::NodeId),
147+
ZeroAndMaintain(ast::NodeId),
148+
None,
149+
}
150+
151+
impl DropFlagInfo {
152+
pub fn must_zero(&self) -> bool {
153+
match *self {
154+
DropFlagInfo::DontZeroJustUse(..) => false,
155+
DropFlagInfo::ZeroAndMaintain(..) => true,
156+
DropFlagInfo::None => true,
157+
}
158+
}
159+
160+
pub fn hint_to_maintain(&self) -> Option<ast::NodeId> {
161+
match *self {
162+
DropFlagInfo::DontZeroJustUse(id) => Some(id),
163+
DropFlagInfo::ZeroAndMaintain(id) => Some(id),
164+
DropFlagInfo::None => None,
165+
}
166+
}
167+
}
168+
169+
// FIXME: having Lvalue be `Copy` is a bit of a footgun, since clients
170+
// may not realize that subparts of an Lvalue can have a subset of
171+
// drop-flags associated with them, while this as written will just
172+
// memcpy the drop_flag_info. But, it is an easier way to get `_match`
173+
// off the ground to just let this be `Copy` for now.
174+
#[derive(Copy, Clone, Debug)]
175+
pub struct Lvalue {
176+
pub source: &'static str,
177+
pub drop_flag_info: DropFlagInfo
178+
}
146179

147180
#[derive(Debug)]
148181
pub struct Rvalue {
149182
pub mode: RvalueMode
150183
}
151184

185+
impl Lvalue {
186+
pub fn new(source: &'static str) -> Lvalue {
187+
Lvalue { source: source, drop_flag_info: DropFlagInfo::None }
188+
}
189+
190+
pub fn upvar<'blk, 'tcx>(source: &'static str,
191+
bcx: Block<'blk, 'tcx>,
192+
id: ast::NodeId) -> Lvalue {
193+
let info = if Lvalue::has_dropflag_hint(bcx, id) {
194+
DropFlagInfo::ZeroAndMaintain(id)
195+
} else {
196+
DropFlagInfo::None
197+
};
198+
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
199+
debug!("upvar Lvalue at {}, id: {} info: {:?}", source, id, info);
200+
Lvalue { source: source, drop_flag_info: info }
201+
}
202+
203+
pub fn match_input<'blk, 'tcx>(source: &'static str,
204+
bcx: Block<'blk, 'tcx>,
205+
id: ast::NodeId) -> Lvalue
206+
{
207+
let info = if Lvalue::has_dropflag_hint(bcx, id) {
208+
// match_input is used to move from the input into a
209+
// separate stack slot; it must zero (at least until we
210+
// improve things to track drop flags for the fragmented
211+
// parent match input expression).
212+
DropFlagInfo::ZeroAndMaintain(id)
213+
} else {
214+
DropFlagInfo::None
215+
};
216+
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
217+
debug!("match_input Lvalue at {}, id: {} info: {:?}", source, id, info);
218+
Lvalue { source: source, drop_flag_info: info }
219+
}
220+
221+
pub fn local<'blk, 'tcx>(source: &'static str,
222+
bcx: Block<'blk, 'tcx>,
223+
id: ast::NodeId,
224+
aliases_other_state: bool)
225+
-> Lvalue
226+
{
227+
let info = if Lvalue::has_dropflag_hint(bcx, id) {
228+
if aliases_other_state {
229+
DropFlagInfo::ZeroAndMaintain(id)
230+
} else {
231+
DropFlagInfo::DontZeroJustUse(id)
232+
}
233+
} else {
234+
DropFlagInfo::None
235+
};
236+
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
237+
debug!("local Lvalue at {}, id: {} info: {:?}", source, id, info);
238+
Lvalue { source: source, drop_flag_info: info }
239+
}
240+
241+
pub fn store_arg<'blk, 'tcx>(source: &'static str,
242+
bcx: Block<'blk, 'tcx>,
243+
id: ast::NodeId) -> Lvalue
244+
{
245+
let info = if Lvalue::has_dropflag_hint(bcx, id) {
246+
DropFlagInfo::ZeroAndMaintain(id)
247+
} else {
248+
DropFlagInfo::None
249+
};
250+
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
251+
debug!("store_arg Lvalue at {}, id: {} info: {:?}", source, id, info);
252+
Lvalue { source: source, drop_flag_info: info }
253+
}
254+
255+
pub fn binding<'blk, 'tcx>(source: &'static str,
256+
bcx: Block<'blk, 'tcx>,
257+
id: ast::NodeId,
258+
name: ast::Name) -> Lvalue {
259+
let info = if Lvalue::has_dropflag_hint(bcx, id) {
260+
DropFlagInfo::DontZeroJustUse(id)
261+
} else {
262+
DropFlagInfo::None
263+
};
264+
let info = if bcx.tcx().sess.nonzeroing_move_hints() { info } else { DropFlagInfo::None };
265+
debug!("binding Lvalue at {}, id: {} name: {} info: {:?}",
266+
source, id, name, info);
267+
Lvalue { source: source, drop_flag_info: info }
268+
}
269+
270+
fn has_dropflag_hint<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
271+
id: ast::NodeId) -> bool {
272+
bcx.fcx.lldropflag_hints.borrow().has_hint(id)
273+
}
274+
}
275+
152276
impl Rvalue {
153277
pub fn new(m: RvalueMode) -> Rvalue {
154278
Rvalue { mode: m }
@@ -201,7 +325,7 @@ pub fn lvalue_scratch_datum<'blk, 'tcx, A, F>(bcx: Block<'blk, 'tcx>,
201325
bcx.fcx.schedule_lifetime_end(scope, scratch);
202326
bcx.fcx.schedule_drop_mem(scope, scratch, ty);
203327

204-
DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue))
328+
DatumBlock::new(bcx, Datum::new(scratch, ty, Lvalue::new("datum::lvalue_scratch_datum")))
205329
}
206330

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

310434
fn to_expr_kind(self) -> Expr {
311-
LvalueExpr
435+
LvalueExpr(self)
312436
}
313437
}
314438

@@ -319,14 +443,14 @@ impl KindOps for Expr {
319443
ty: Ty<'tcx>)
320444
-> Block<'blk, 'tcx> {
321445
match *self {
322-
LvalueExpr => Lvalue.post_store(bcx, val, ty),
446+
LvalueExpr(ref l) => l.post_store(bcx, val, ty),
323447
RvalueExpr(ref r) => r.post_store(bcx, val, ty),
324448
}
325449
}
326450

327451
fn is_by_ref(&self) -> bool {
328452
match *self {
329-
LvalueExpr => Lvalue.is_by_ref(),
453+
LvalueExpr(ref l) => l.is_by_ref(),
330454
RvalueExpr(ref r) => r.is_by_ref()
331455
}
332456
}
@@ -360,7 +484,10 @@ impl<'tcx> Datum<'tcx, Rvalue> {
360484
match self.kind.mode {
361485
ByRef => {
362486
add_rvalue_clean(ByRef, fcx, scope, self.val, self.ty);
363-
DatumBlock::new(bcx, Datum::new(self.val, self.ty, Lvalue))
487+
DatumBlock::new(bcx, Datum::new(
488+
self.val,
489+
self.ty,
490+
Lvalue::new("datum::to_lvalue_datum_in_scope")))
364491
}
365492

366493
ByValue => {
@@ -417,7 +544,7 @@ impl<'tcx> Datum<'tcx, Expr> {
417544
{
418545
let Datum { val, ty, kind } = self;
419546
match kind {
420-
LvalueExpr => if_lvalue(Datum::new(val, ty, Lvalue)),
547+
LvalueExpr(l) => if_lvalue(Datum::new(val, ty, l)),
421548
RvalueExpr(r) => if_rvalue(Datum::new(val, ty, r)),
422549
}
423550
}
@@ -528,7 +655,7 @@ impl<'tcx> Datum<'tcx, Lvalue> {
528655
};
529656
Datum {
530657
val: val,
531-
kind: Lvalue,
658+
kind: Lvalue::new("Datum::get_element"),
532659
ty: ty,
533660
}
534661
}

0 commit comments

Comments
 (0)