inliner: Emit storage markers for introduced arg temporaries

When introducing argument temporaries during inlining, emit storage
marker statements just before the assignment and in the beginning of
the return block.

This ensures that such temporaries will not be considered live across
yield points after inlining inside a generator.
This commit is contained in:
Tomasz Miąsko 2020-09-03 00:00:00 +00:00
parent 08deb863bd
commit 9daf8fd5b1
6 changed files with 58 additions and 8 deletions

View File

@ -494,7 +494,7 @@ impl Inliner<'tcx> {
let return_block = destination.1; let return_block = destination.1;
// Copy the arguments if needed. // Copy the arguments if needed.
let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block);
let bb_len = caller_body.basic_blocks().len(); let bb_len = caller_body.basic_blocks().len();
let mut integrator = Integrator { let mut integrator = Integrator {
@ -541,6 +541,7 @@ impl Inliner<'tcx> {
args: Vec<Operand<'tcx>>, args: Vec<Operand<'tcx>>,
callsite: &CallSite<'tcx>, callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>, caller_body: &mut Body<'tcx>,
return_block: BasicBlock,
) -> Vec<Local> { ) -> Vec<Local> {
let tcx = self.tcx; let tcx = self.tcx;
@ -569,8 +570,18 @@ impl Inliner<'tcx> {
// and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`.
if tcx.is_closure(callsite.callee) { if tcx.is_closure(callsite.callee) {
let mut args = args.into_iter(); let mut args = args.into_iter();
let self_ = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); let self_ = self.create_temp_if_necessary(
let tuple = self.create_temp_if_necessary(args.next().unwrap(), callsite, caller_body); args.next().unwrap(),
callsite,
caller_body,
return_block,
);
let tuple = self.create_temp_if_necessary(
args.next().unwrap(),
callsite,
caller_body,
return_block,
);
assert!(args.next().is_none()); assert!(args.next().is_none());
let tuple = Place::from(tuple); let tuple = Place::from(tuple);
@ -590,13 +601,13 @@ impl Inliner<'tcx> {
Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty())); Operand::Move(tcx.mk_place_field(tuple, Field::new(i), ty.expect_ty()));
// Spill to a local to make e.g., `tmp0`. // Spill to a local to make e.g., `tmp0`.
self.create_temp_if_necessary(tuple_field, callsite, caller_body) self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block)
}); });
closure_ref_arg.chain(tuple_tmp_args).collect() closure_ref_arg.chain(tuple_tmp_args).collect()
} else { } else {
args.into_iter() args.into_iter()
.map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block))
.collect() .collect()
} }
} }
@ -608,6 +619,7 @@ impl Inliner<'tcx> {
arg: Operand<'tcx>, arg: Operand<'tcx>,
callsite: &CallSite<'tcx>, callsite: &CallSite<'tcx>,
caller_body: &mut Body<'tcx>, caller_body: &mut Body<'tcx>,
return_block: BasicBlock,
) -> Local { ) -> Local {
// FIXME: Analysis of the usage of the arguments to avoid // FIXME: Analysis of the usage of the arguments to avoid
// unnecessary temporaries. // unnecessary temporaries.
@ -630,11 +642,19 @@ impl Inliner<'tcx> {
let arg_tmp = LocalDecl::new(ty, callsite.location.span); let arg_tmp = LocalDecl::new(ty, callsite.location.span);
let arg_tmp = caller_body.local_decls.push(arg_tmp); let arg_tmp = caller_body.local_decls.push(arg_tmp);
let stmt = Statement { caller_body[callsite.bb].statements.push(Statement {
source_info: callsite.location,
kind: StatementKind::StorageLive(arg_tmp),
});
caller_body[callsite.bb].statements.push(Statement {
source_info: callsite.location, source_info: callsite.location,
kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)), kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)),
}; });
caller_body[callsite.bb].statements.push(stmt); caller_body[return_block].statements.insert(
0,
Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) },
);
arg_tmp arg_tmp
} }
} }

View File

@ -22,9 +22,13 @@ fn bar() -> bool {
// + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) } // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar(<ZST>)) }
StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
_2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6
StorageLive(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageLive(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
_0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11
StorageDead(_4); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageDead(_3); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13
StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13
StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2
return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2

View File

@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 {
_7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 _7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11
(_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
(_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
_0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24 _0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24
StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12
StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12
StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12

View File

@ -33,9 +33,13 @@ fn foo(_1: T, _2: &i32) -> i32 {
_7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11
(_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
(_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageLive(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
_0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18
StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageDead(_8); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12
StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12
StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12

View File

@ -38,6 +38,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
_8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8
(_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
_11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
_9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20
@ -47,6 +48,7 @@ fn foo(_1: T, _2: i32) -> (i32, T) {
(_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24
StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24
StorageDead(_11); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9
StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9
StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9

View File

@ -0,0 +1,16 @@
// Verifies that inliner emits StorageLive & StorageDead when introducing
// temporaries for arguments, so that they don't become part of the generator.
// Regression test for #71793.
//
// check-pass
// edition:2018
// compile-args: -Zmir-opt-level=2
#![crate_type = "lib"]
pub async fn connect() {}
pub async fn connect_many() {
Vec::<String>::new().first().ok_or("").unwrap();
connect().await;
}