Skip to content

Commit af63f8d

Browse files
committed
Various hacks around storage statements
1 parent 6685e6b commit af63f8d

3 files changed

Lines changed: 91 additions & 46 deletions

File tree

compiler/rustc_mir_build/src/builder/scope.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -268,7 +268,7 @@ impl Scope {
268268
fn needs_cleanup(&self) -> bool {
269269
self.drops.iter().any(|drop| match drop.kind {
270270
DropKind::Value | DropKind::ForLint => true,
271-
DropKind::Storage => false,
271+
DropKind::Storage => true,
272272
})
273273
}
274274

@@ -1239,7 +1239,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
12391239
block,
12401240
unwind_to,
12411241
dropline_to,
1242-
is_coroutine && needs_cleanup,
1242+
true && needs_cleanup,
12431243
self.arg_count,
12441244
|v: Local| Self::is_async_drop_impl(self.tcx, &self.local_decls, typing_env, v),
12451245
)
@@ -1479,7 +1479,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
14791479
// path, we only need to invalidate the cache for drops that happen on
14801480
// the unwind or coroutine drop paths. This means that for
14811481
// non-coroutines we don't need to invalidate caches for `DropKind::Storage`.
1482-
let invalidate_caches = needs_drop || self.coroutine.is_some();
1482+
let invalidate_caches = needs_drop || self.coroutine.is_some() || true;
14831483
for scope in self.scopes.scopes.iter_mut().rev() {
14841484
if invalidate_caches {
14851485
scope.invalidate_cache();
@@ -1630,7 +1630,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16301630
let is_coroutine = self.coroutine.is_some();
16311631
for scope in &mut self.scopes.scopes[uncached_scope..=target] {
16321632
for drop in &scope.drops {
1633-
if is_coroutine || drop.kind == DropKind::Value {
1633+
if is_coroutine || true || drop.kind == DropKind::Value {
16341634
cached_drop = self.scopes.unwind_drops.add_drop(*drop, cached_drop);
16351635
}
16361636
}
@@ -2005,7 +2005,7 @@ impl<'a, 'tcx: 'a> Builder<'a, 'tcx> {
20052005
for (drop_idx, drop_node) in drops.drop_nodes.iter_enumerated().skip(1) {
20062006
match drop_node.data.kind {
20072007
DropKind::Storage | DropKind::ForLint => {
2008-
if is_coroutine {
2008+
if true || is_coroutine {
20092009
let unwind_drop = self
20102010
.scopes
20112011
.unwind_drops

compiler/rustc_mir_transform/src/inline.rs

Lines changed: 58 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -904,7 +904,7 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
904904
destination,
905905
);
906906
let dest_ty = dest.ty(caller_body, tcx);
907-
let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block));
907+
let temp = Place::from(new_call_temp(caller_body, callsite, dest_ty, return_block, unwind));
908908
caller_body[callsite.block].statements.push(Statement::new(
909909
callsite.source_info,
910910
StatementKind::Assign(Box::new((temp, dest))),
@@ -921,12 +921,19 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
921921
} else {
922922
(
923923
true,
924-
new_call_temp(caller_body, callsite, destination.ty(caller_body, tcx).ty, return_block),
924+
new_call_temp(
925+
caller_body,
926+
callsite,
927+
destination.ty(caller_body, tcx).ty,
928+
return_block,
929+
unwind,
930+
),
925931
)
926932
};
927933

928934
// Copy the arguments if needed.
929-
let args = make_call_args(inliner, args, callsite, caller_body, &callee_body, return_block);
935+
let args =
936+
make_call_args(inliner, args, callsite, caller_body, &callee_body, return_block, unwind);
930937

931938
let mut integrator = Integrator {
932939
args: &args,
@@ -983,6 +990,25 @@ fn inline_call<'tcx, I: Inliner<'tcx>>(
983990
}
984991
caller_body[block].statements.rotate_right(n);
985992
}
993+
if let UnwindAction::Cleanup(block) = unwind {
994+
// To avoid repeated O(n) insert, push any new statements to the end and rotate
995+
// the slice once.
996+
let mut n = 0;
997+
for local in callee_body.vars_and_temps_iter().rev() {
998+
// Do this for *all* locals instead of just the always-live ones.
999+
// This is necessary because StorageDead is often not preserved on
1000+
// unwind paths.
1001+
//
1002+
// FIXME: Restrict this to only locals that are storage-live at an
1003+
// UnwindAction::Continue.
1004+
let new_local = integrator.map_local(local);
1005+
caller_body[block]
1006+
.statements
1007+
.push(Statement::new(callsite.source_info, StatementKind::StorageDead(new_local)));
1008+
n += 1;
1009+
}
1010+
caller_body[block].statements.rotate_right(n);
1011+
}
9861012

9871013
// Insert all of the (mapped) parts of the callee body into the caller.
9881014
caller_body.local_decls.extend(callee_body.drain_vars_and_temps());
@@ -1045,6 +1071,7 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
10451071
caller_body: &mut Body<'tcx>,
10461072
callee_body: &Body<'tcx>,
10471073
return_block: Option<BasicBlock>,
1074+
unwind: UnwindAction,
10481075
) -> Box<[Local]> {
10491076
let tcx = inliner.tcx();
10501077

@@ -1080,13 +1107,15 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
10801107
callsite,
10811108
caller_body,
10821109
return_block,
1110+
unwind,
10831111
);
10841112
let tuple = create_temp_if_necessary(
10851113
inliner,
10861114
args.next().unwrap().node,
10871115
callsite,
10881116
caller_body,
10891117
return_block,
1118+
unwind,
10901119
);
10911120
assert!(args.next().is_none());
10921121

@@ -1104,13 +1133,29 @@ fn make_call_args<'tcx, I: Inliner<'tcx>>(
11041133
let tuple_field = Operand::Move(tcx.mk_place_field(tuple, FieldIdx::new(i), ty));
11051134

11061135
// Spill to a local to make e.g., `tmp0`.
1107-
create_temp_if_necessary(inliner, tuple_field, callsite, caller_body, return_block)
1136+
create_temp_if_necessary(
1137+
inliner,
1138+
tuple_field,
1139+
callsite,
1140+
caller_body,
1141+
return_block,
1142+
unwind,
1143+
)
11081144
});
11091145

11101146
closure_ref_arg.chain(tuple_tmp_args).collect()
11111147
} else {
11121148
args.into_iter()
1113-
.map(|a| create_temp_if_necessary(inliner, a.node, callsite, caller_body, return_block))
1149+
.map(|a| {
1150+
create_temp_if_necessary(
1151+
inliner,
1152+
a.node,
1153+
callsite,
1154+
caller_body,
1155+
return_block,
1156+
unwind,
1157+
)
1158+
})
11141159
.collect()
11151160
}
11161161
}
@@ -1123,6 +1168,7 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
11231168
callsite: &CallSite<'tcx>,
11241169
caller_body: &mut Body<'tcx>,
11251170
return_block: Option<BasicBlock>,
1171+
unwind: UnwindAction,
11261172
) -> Local {
11271173
// Reuse the operand if it is a moved temporary.
11281174
if let Operand::Move(place) = &arg
@@ -1135,7 +1181,7 @@ fn create_temp_if_necessary<'tcx, I: Inliner<'tcx>>(
11351181
// Otherwise, create a temporary for the argument.
11361182
trace!("creating temp for argument {:?}", arg);
11371183
let arg_ty = arg.ty(caller_body, inliner.tcx());
1138-
let local = new_call_temp(caller_body, callsite, arg_ty, return_block);
1184+
let local = new_call_temp(caller_body, callsite, arg_ty, return_block, unwind);
11391185
caller_body[callsite.block].statements.push(Statement::new(
11401186
callsite.source_info,
11411187
StatementKind::Assign(Box::new((Place::from(local), Rvalue::Use(arg, WithRetag::Yes)))),
@@ -1149,6 +1195,7 @@ fn new_call_temp<'tcx>(
11491195
callsite: &CallSite<'tcx>,
11501196
ty: Ty<'tcx>,
11511197
return_block: Option<BasicBlock>,
1198+
unwind: UnwindAction,
11521199
) -> Local {
11531200
let local = caller_body.local_decls.push(LocalDecl::new(ty, callsite.source_info.span));
11541201

@@ -1161,6 +1208,11 @@ fn new_call_temp<'tcx>(
11611208
.statements
11621209
.insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local)));
11631210
}
1211+
if let UnwindAction::Cleanup(block) = unwind {
1212+
caller_body[block]
1213+
.statements
1214+
.insert(0, Statement::new(callsite.source_info, StatementKind::StorageDead(local)));
1215+
}
11641216

11651217
local
11661218
}

compiler/rustc_mir_transform/src/move_elimination.rs

Lines changed: 28 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -39,12 +39,12 @@ impl<'tcx> crate::MirPass<'tcx> for MoveElimination {
3939
let remapped_locals =
4040
PlaceUnification::run(tcx, body, &mut liveness_matrix, &mut unprojectable_locals);
4141

42-
dump_liveness_matrix(tcx, body, "MoveElimination.post-liveness", &points, &liveness_matrix);
42+
apply_mappings(tcx, body, &remapped_locals);
4343

44-
let storage_to_rebuild = apply_mappings(tcx, body, &remapped_locals);
44+
dump_liveness_matrix(tcx, body, "MoveElimination.post-liveness", &points, &liveness_matrix);
4545

4646
if tcx.sess.emit_lifetime_markers() {
47-
reconstruct_storage(body, &points, &liveness_matrix, &storage_to_rebuild);
47+
reconstruct_storage(body, &points, &liveness_matrix);
4848
}
4949

5050
apply_alias_fixup(tcx, body);
@@ -377,26 +377,14 @@ fn apply_mappings<'tcx>(
377377
tcx: TyCtxt<'tcx>,
378378
body: &mut Body<'tcx>,
379379
remapped_locals: &IndexVec<Local, Option<Place<'tcx>>>,
380-
) -> DenseBitSet<Local> {
381-
let mut unified_locals = DenseBitSet::new_empty(body.local_decls.len());
382-
for (src, dst) in remapped_locals.iter_enumerated() {
383-
if let Some(dst_place) = dst {
384-
unified_locals.insert(src);
385-
unified_locals.insert(dst_place.local);
386-
}
387-
}
388-
389-
let storage_to_rebuild = DenseBitSet::new_empty(body.local_decls.len());
390-
let mut rewriter = PlaceUpdater { tcx, remapped_locals, unified_locals, storage_to_rebuild };
380+
) {
381+
let mut rewriter = PlaceUpdater { tcx, remapped_locals };
391382
rewriter.visit_body_preserves_cfg(body);
392-
rewriter.storage_to_rebuild
393383
}
394384

395385
struct PlaceUpdater<'a, 'tcx> {
396386
tcx: TyCtxt<'tcx>,
397387
remapped_locals: &'a IndexVec<Local, Option<Place<'tcx>>>,
398-
unified_locals: DenseBitSet<Local>,
399-
storage_to_rebuild: DenseBitSet<Local>,
400388
}
401389

402390
impl<'tcx> MutVisitor<'tcx> for PlaceUpdater<'_, 'tcx> {
@@ -425,17 +413,11 @@ impl<'tcx> MutVisitor<'tcx> for PlaceUpdater<'_, 'tcx> {
425413

426414
fn visit_statement(&mut self, statement: &mut Statement<'tcx>, location: Location) {
427415
match statement.kind {
428-
StatementKind::StorageDead(local) | StatementKind::StorageLive(local)
429-
if self.unified_locals.contains(local) =>
430-
{
431-
// Only rebuild storage for locals that previously had storage
432-
// statements.
433-
let mapped_local = match self.remapped_locals[local] {
434-
Some(place) => place.local,
435-
None => local,
436-
};
437-
self.storage_to_rebuild.insert(mapped_local);
438-
416+
// Remove *all* storage statements. These are rebuilt from liveness
417+
// information later. Also, since we've preserved StorageDead in
418+
// unwind paths until now, we will want to remove those since they
419+
// hurt LLVM's codegen.
420+
StatementKind::StorageDead(_) | StatementKind::StorageLive(_) => {
439421
statement.make_nop(true);
440422
return;
441423
}
@@ -481,16 +463,11 @@ fn reconstruct_storage<'tcx>(
481463
body: &mut Body<'tcx>,
482464
points: &DenseLocationMap,
483465
liveness_matrix: &SparseIntervalMatrix<Local, SplitPointIndex>,
484-
storage_to_rebuild: &DenseBitSet<Local>,
485466
) {
486467
let mut patcher = MirPatch::new(body);
487468
let mut split_edges: FxHashMap<(BasicBlock, BasicBlock), BasicBlock> = Default::default();
488469

489470
for local in body.local_decls.indices() {
490-
if !storage_to_rebuild.contains(local) {
491-
continue;
492-
}
493-
494471
// Arguments and return values don't use storage statements.
495472
match body.local_kind(local) {
496473
LocalKind::Arg | LocalKind::ReturnPointer => continue,
@@ -511,6 +488,11 @@ fn reconstruct_storage<'tcx>(
511488
local: Local,
512489
block: BasicBlock| {
513490
for &pred in &body.basic_blocks.predecessors()[block].clone() {
491+
// HACK: Don't insert StorageLive in cleanup blocks
492+
if body.basic_blocks[pred].is_cleanup {
493+
continue;
494+
}
495+
514496
// If the local is live at any point in the predecessor's
515497
// terminator then no StorageLive is needed.
516498
let term_early =
@@ -543,8 +525,14 @@ fn reconstruct_storage<'tcx>(
543525
local: Local,
544526
block: BasicBlock| {
545527
for succ in body.basic_blocks[block].terminator().successors() {
546-
// Don't emit StorageDead in cleanup blocks.
547-
if body.basic_blocks[succ].is_cleanup {
528+
// Don't emit StorageDead in cleanup blocks and
529+
// unreachable blocks.
530+
if body.basic_blocks[succ].is_cleanup
531+
|| matches!(
532+
body.basic_blocks[succ].terminator().kind,
533+
TerminatorKind::Unreachable
534+
)
535+
{
548536
continue;
549537
}
550538

@@ -583,6 +571,11 @@ fn reconstruct_storage<'tcx>(
583571
// emit a `StorageLive` before the terminator.
584572
emit_storage_live_in_preds(body, &mut patcher, local, start_block);
585573
} else {
574+
// HACK: Don't insert StorageLive in cleanup blocks
575+
if body.basic_blocks[start_block].is_cleanup {
576+
continue;
577+
}
578+
586579
// Otherwise just add `StorageLive` before the statement that
587580
// starts the live range.
588581
patcher.add_statement(

0 commit comments

Comments
 (0)