Skip to content

Commit 69d1abe

Browse files
committed
[SIL] Protect owned arg lifetimes at inlining.
Previously, `begin_borrow [lexical]` were created during SILGen for @owned arguments. Such borrows could be deleted if trivially dead, which was the original reason why @owned arguments were considered lexical and could not have their destroys hoisted. Those borrows were however important during inlining because they would maintain the lifetime of the owned argument. Unless of course the borrow scope was trivially dead. In which case the owned argument's lifetime would not be maintained. And if the caller's value was non-lexical, destroys of the value could be hoisted over deinit barriers. Here, during inlining, `move_value [lexical]`s are introduced during inlining whever the caller's value is non-lexical. This maintains the lifetime of the owned argument even after inlining.
1 parent 6e97889 commit 69d1abe

File tree

3 files changed

+34
-9
lines changed

3 files changed

+34
-9
lines changed

docs/SIL.rst

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2458,6 +2458,12 @@ That the first three have constrained lifetimes is encoded in
24582458
ValueBase::isLexical, which should be checked before changing the lifetime of a
24592459
value.
24602460

2461+
When a function is inlined into its caller, a lexical borrow scope is added for
2462+
each of its @guaranteed arguments, and a lexical move is added for each of its
2463+
@owned arguments, (unless the values being passed are already lexical
2464+
themselves) ensuring that the lifetimes of the corresponding source-level
2465+
values are not shortened in a way that doesn't respect deinit barriers.
2466+
24612467
Unlike the other sorts, `alloc_stack [lexical]` isn't a SILValue. Instead, it
24622468
constrains the lifetime of an addressable variable. Since the constraint is
24632469
applied to the in-memory representation, no additional lexical SILValue is

lib/SILGen/SILGenProlog.cpp

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -303,15 +303,8 @@ struct ArgumentInitHelper {
303303
// form.
304304
if (!isNoImplicitCopy) {
305305
if (!value->getType().isMoveOnly()) {
306-
// Follow the "normal path": perform a lexical borrow if the lifetime is
307-
// lexical.
308-
if (value->getOwnershipKind() == OwnershipKind::Owned) {
309-
if (lifetime.isLexical()) {
310-
value = SILValue(
311-
SGF.B.createBeginBorrow(loc, value, /*isLexical*/ true));
312-
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(value);
313-
}
314-
}
306+
// Follow the normal path. The value's lifetime will be enforced based
307+
// on its ownership.
315308
return value;
316309
}
317310

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -306,6 +306,7 @@ class SILInlineCloner
306306

307307
protected:
308308
SILValue borrowFunctionArgument(SILValue callArg, unsigned index);
309+
SILValue moveFunctionArgument(SILValue callArg, unsigned index);
309310

310311
void visitDebugValueInst(DebugValueInst *Inst);
311312
void visitHopToExecutorInst(HopToExecutorInst *Inst);
@@ -489,6 +490,10 @@ void SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) {
489490
callArg = newValue;
490491
borrowedArgs[idx] = true;
491492
}
493+
} else if (paramInfo.isConsumed()) {
494+
if (SILValue newValue = moveFunctionArgument(callArg, idx)) {
495+
callArg = newValue;
496+
}
492497
}
493498
}
494499
}
@@ -652,6 +657,7 @@ Scope scopeForArgument(Scope nonlexicalScope, SILValue callArg, unsigned index,
652657
if (!enableLexicalLifetimes) {
653658
// Lexical lifetimes are disabled. Use the non-lexical scope:
654659
// - for borrows, do an ownership conversion.
660+
// - for moves, do nothing.
655661
return nonlexicalScope;
656662
}
657663
if (!argument->getLifetime().isLexical()) {
@@ -703,6 +709,26 @@ SILValue SILInlineCloner::borrowFunctionArgument(SILValue callArg,
703709
return beginBuilder.createBeginBorrow(Apply.getLoc(), callArg, isLexical);
704710
}
705711

712+
SILValue SILInlineCloner::moveFunctionArgument(SILValue callArg,
713+
unsigned index) {
714+
auto scope = scopeForArgument(Scope::None, callArg, index,
715+
Apply.getFunction(), getCalleeFunction());
716+
bool isLexical;
717+
switch (scope) {
718+
case Scope::None:
719+
return SILValue();
720+
case Scope::Bare:
721+
assert(false && "Non-lexical move produced during inlining!?");
722+
isLexical = false;
723+
break;
724+
case Scope::Lexical:
725+
isLexical = true;
726+
break;
727+
}
728+
SILBuilderWithScope beginBuilder(Apply.getInstruction(), getBuilder());
729+
return beginBuilder.createMoveValue(Apply.getLoc(), callArg, isLexical);
730+
}
731+
706732
void SILInlineCloner::visitDebugValueInst(DebugValueInst *Inst) {
707733
// The mandatory inliner drops debug_value instructions when inlining, as if
708734
// it were a "nodebug" function in C.

0 commit comments

Comments
 (0)