Skip to content

Commit 1d5b758

Browse files
authored
Auto merge of #35409 - eddyb:mir-storage-stmts, r=nikomatsakis
[MIR] Add Storage{Live,Dead} statements to emit llvm.lifetime.{start,end}. Storage live ranges are tracked for all MIR variables and temporaries with a drop scope. `StorageLive` is lowered to `llvm.lifetime.start` and `StorageDead` to `llvm.lifetime.end`. There are some improvements possible here, such as: * pack multiple storage liveness statements by using the index of first local + `u64` bitset * enforce that locals are not directly accessed outside their storage live range * shrink storage live ranges for never-borrowed locals to initialization -> last use * emit storage liveness statements for *all* temporaries * however, the remaining ones are *always* SSA immediates, so they'd be noop in MIR trans * could have a flag on the temporary that its storage is irrelevant (a la C's old `register`) * would also deny borrows if necessary * this seems like an overcompliation and with packing & optimizations it may be pointless Even in the current state, it helps stage2 `rustc` compile `boiler` without overflowing (see #35408). A later addition fixes #26764 and closes #27372 by emitting `.section` directives for dylib metadata to avoid them being allocated into memory or read as `.note`. For this PR, those bugs were tripping valgrind.
2 parents 92ae4ce + 1bb1444 commit 1d5b758

File tree

23 files changed

+387
-85
lines changed

23 files changed

+387
-85
lines changed

src/librustc/mir/repr.rs

+12-1
Original file line numberDiff line numberDiff line change
@@ -688,15 +688,26 @@ pub struct Statement<'tcx> {
688688

689689
#[derive(Clone, Debug, RustcEncodable, RustcDecodable)]
690690
pub enum StatementKind<'tcx> {
691+
/// Write the RHS Rvalue to the LHS Lvalue.
691692
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
692-
SetDiscriminant{ lvalue: Lvalue<'tcx>, variant_index: usize },
693+
694+
/// Write the discriminant for a variant to the enum Lvalue.
695+
SetDiscriminant { lvalue: Lvalue<'tcx>, variant_index: usize },
696+
697+
/// Start a live range for the storage of the local.
698+
StorageLive(Lvalue<'tcx>),
699+
700+
/// End the current live range for the storage of the local.
701+
StorageDead(Lvalue<'tcx>),
693702
}
694703

695704
impl<'tcx> Debug for Statement<'tcx> {
696705
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
697706
use self::StatementKind::*;
698707
match self.kind {
699708
Assign(ref lv, ref rv) => write!(fmt, "{:?} = {:?}", lv, rv),
709+
StorageLive(ref lv) => write!(fmt, "StorageLive({:?})", lv),
710+
StorageDead(ref lv) => write!(fmt, "StorageDead({:?})", lv),
700711
SetDiscriminant{lvalue: ref lv, variant_index: index} => {
701712
write!(fmt, "discriminant({:?}) = {:?}", lv, index)
702713
}

src/librustc/mir/visit.rs

+10
Original file line numberDiff line numberDiff line change
@@ -326,6 +326,12 @@ macro_rules! make_mir_visitor {
326326
StatementKind::SetDiscriminant{ ref $($mutability)* lvalue, .. } => {
327327
self.visit_lvalue(lvalue, LvalueContext::Store);
328328
}
329+
StatementKind::StorageLive(ref $($mutability)* lvalue) => {
330+
self.visit_lvalue(lvalue, LvalueContext::StorageLive);
331+
}
332+
StatementKind::StorageDead(ref $($mutability)* lvalue) => {
333+
self.visit_lvalue(lvalue, LvalueContext::StorageDead);
334+
}
329335
}
330336
}
331337

@@ -759,4 +765,8 @@ pub enum LvalueContext {
759765

760766
// Consumed as part of an operand
761767
Consume,
768+
769+
// Starting and ending a storage live range
770+
StorageLive,
771+
StorageDead,
762772
}

src/librustc_borrowck/borrowck/mir/dataflow/impls.rs

+2
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,8 @@ impl<'a, 'tcx> BitDenotation for MovingOutStatements<'a, 'tcx> {
459459
sets.kill_set.add(&moi);
460460
});
461461
}
462+
repr::StatementKind::StorageLive(_) |
463+
repr::StatementKind::StorageDead(_) => {}
462464
}
463465
}
464466

src/librustc_borrowck/borrowck/mir/dataflow/sanity_check.rs

+2
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,8 @@ fn each_block<'a, 'tcx, O>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
104104
repr::StatementKind::Assign(ref lvalue, ref rvalue) => {
105105
(lvalue, rvalue)
106106
}
107+
repr::StatementKind::StorageLive(_) |
108+
repr::StatementKind::StorageDead(_) => continue,
107109
repr::StatementKind::SetDiscriminant{ .. } =>
108110
span_bug!(stmt.source_info.span,
109111
"sanity_check should run before Deaggregator inserts SetDiscriminant"),

src/librustc_borrowck/borrowck/mir/gather_moves.rs

+2
Original file line numberDiff line numberDiff line change
@@ -616,6 +616,8 @@ fn gather_moves<'a, 'tcx>(mir: &Mir<'tcx>, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> MoveD
616616
Rvalue::InlineAsm { .. } => {}
617617
}
618618
}
619+
StatementKind::StorageLive(_) |
620+
StatementKind::StorageDead(_) => {}
619621
StatementKind::SetDiscriminant{ .. } => {
620622
span_bug!(stmt.source_info.span,
621623
"SetDiscriminant should not exist during borrowck");

src/librustc_borrowck/borrowck/mir/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -378,6 +378,8 @@ fn drop_flag_effects_for_location<'a, 'tcx, F>(
378378
move_data.rev_lookup.find(lvalue),
379379
|moi| callback(moi, DropFlagState::Present))
380380
}
381+
repr::StatementKind::StorageLive(_) |
382+
repr::StatementKind::StorageDead(_) => {}
381383
},
382384
None => {
383385
debug!("drop_flag_effects: replace {:?}", block.terminator());

src/librustc_metadata/loader.rs

+18-23
Original file line numberDiff line numberDiff line change
@@ -867,34 +867,29 @@ fn get_metadata_section_imp(target: &Target, flavor: CrateFlavor, filename: &Pat
867867
}
868868

869869
pub fn meta_section_name(target: &Target) -> &'static str {
870+
// Historical note:
871+
//
872+
// When using link.exe it was seen that the section name `.note.rustc`
873+
// was getting shortened to `.note.ru`, and according to the PE and COFF
874+
// specification:
875+
//
876+
// > Executable images do not use a string table and do not support
877+
// > section names longer than 8 characters
878+
//
879+
// https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
880+
//
881+
// As a result, we choose a slightly shorter name! As to why
882+
// `.note.rustc` works on MinGW, that's another good question...
883+
870884
if target.options.is_like_osx {
871-
"__DATA,__note.rustc"
872-
} else if target.options.is_like_msvc {
873-
// When using link.exe it was seen that the section name `.note.rustc`
874-
// was getting shortened to `.note.ru`, and according to the PE and COFF
875-
// specification:
876-
//
877-
// > Executable images do not use a string table and do not support
878-
// > section names longer than 8 characters
879-
//
880-
// https://msdn.microsoft.com/en-us/library/windows/hardware/gg463119.aspx
881-
//
882-
// As a result, we choose a slightly shorter name! As to why
883-
// `.note.rustc` works on MinGW, that's another good question...
884-
".rustc"
885+
"__DATA,.rustc"
885886
} else {
886-
".note.rustc"
887+
".rustc"
887888
}
888889
}
889890

890-
pub fn read_meta_section_name(target: &Target) -> &'static str {
891-
if target.options.is_like_osx {
892-
"__note.rustc"
893-
} else if target.options.is_like_msvc {
894-
".rustc"
895-
} else {
896-
".note.rustc"
897-
}
891+
pub fn read_meta_section_name(_target: &Target) -> &'static str {
892+
".rustc"
898893
}
899894

900895
// A diagnostic function for dumping crate metadata to an output stream

src/librustc_mir/build/block.rs

+2
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,8 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
6868
// FIXME #30046 ^~~~
6969
this.expr_into_pattern(block, pattern, init)
7070
}));
71+
} else {
72+
this.storage_live_for_bindings(block, &pattern);
7173
}
7274

7375
// Enter the visibility scope, after evaluating the initializer.

src/librustc_mir/build/expr/as_temp.rs

+8-1
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,14 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
3737
let temp = this.temp(expr_ty.clone());
3838
let temp_lifetime = expr.temp_lifetime;
3939
let expr_span = expr.span;
40+
let source_info = this.source_info(expr_span);
41+
42+
if temp_lifetime.is_some() {
43+
this.cfg.push(block, Statement {
44+
source_info: source_info,
45+
kind: StatementKind::StorageLive(temp.clone())
46+
});
47+
}
4048

4149
// Careful here not to cause an infinite cycle. If we always
4250
// called `into`, then for lvalues like `x.f`, it would
@@ -49,7 +57,6 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
4957
Category::Lvalue => {
5058
let lvalue = unpack!(block = this.as_lvalue(block, expr));
5159
let rvalue = Rvalue::Use(Operand::Consume(lvalue));
52-
let source_info = this.source_info(expr_span);
5360
this.cfg.push_assign(block, source_info, &temp, rvalue);
5461
}
5562
_ => {

src/librustc_mir/build/matches/mod.rs

+42
Original file line numberDiff line numberDiff line change
@@ -122,6 +122,7 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
122122
PatternKind::Binding { mode: BindingMode::ByValue,
123123
var,
124124
subpattern: None, .. } => {
125+
self.storage_live_for_bindings(block, &irrefutable_pat);
125126
let lvalue = Lvalue::Var(self.var_indices[&var]);
126127
return self.into(&lvalue, block, initializer);
127128
}
@@ -206,6 +207,43 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
206207
}
207208
var_scope
208209
}
210+
211+
/// Emit `StorageLive` for every binding in the pattern.
212+
pub fn storage_live_for_bindings(&mut self,
213+
block: BasicBlock,
214+
pattern: &Pattern<'tcx>) {
215+
match *pattern.kind {
216+
PatternKind::Binding { var, ref subpattern, .. } => {
217+
let lvalue = Lvalue::Var(self.var_indices[&var]);
218+
let source_info = self.source_info(pattern.span);
219+
self.cfg.push(block, Statement {
220+
source_info: source_info,
221+
kind: StatementKind::StorageLive(lvalue)
222+
});
223+
224+
if let Some(subpattern) = subpattern.as_ref() {
225+
self.storage_live_for_bindings(block, subpattern);
226+
}
227+
}
228+
PatternKind::Array { ref prefix, ref slice, ref suffix } |
229+
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
230+
for subpattern in prefix.iter().chain(slice).chain(suffix) {
231+
self.storage_live_for_bindings(block, subpattern);
232+
}
233+
}
234+
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
235+
}
236+
PatternKind::Deref { ref subpattern } => {
237+
self.storage_live_for_bindings(block, subpattern);
238+
}
239+
PatternKind::Leaf { ref subpatterns } |
240+
PatternKind::Variant { ref subpatterns, .. } => {
241+
for subpattern in subpatterns {
242+
self.storage_live_for_bindings(block, &subpattern.pattern);
243+
}
244+
}
245+
}
246+
}
209247
}
210248

211249
/// List of blocks for each arm (and potentially other metadata in the
@@ -665,6 +703,10 @@ impl<'a, 'gcx, 'tcx> Builder<'a, 'gcx, 'tcx> {
665703
};
666704

667705
let source_info = self.source_info(binding.span);
706+
self.cfg.push(block, Statement {
707+
source_info: source_info,
708+
kind: StatementKind::StorageLive(Lvalue::Var(var_index))
709+
});
668710
self.cfg.push_assign(block, source_info,
669711
&Lvalue::Var(var_index), rvalue);
670712
}

src/librustc_mir/build/mod.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -238,7 +238,8 @@ pub fn construct_const<'a, 'gcx, 'tcx>(hir: Cx<'a, 'gcx, 'tcx>,
238238
let span = tcx.map.span(item_id);
239239
let mut builder = Builder::new(hir, span);
240240

241-
let extent = ROOT_CODE_EXTENT;
241+
let extent = tcx.region_maps.temporary_scope(ast_expr.id)
242+
.unwrap_or(ROOT_CODE_EXTENT);
242243
let mut block = START_BLOCK;
243244
let _ = builder.in_scope(extent, block, |builder| {
244245
let expr = builder.hir.mirror(ast_expr);

0 commit comments

Comments
 (0)