Skip to content

Commit 6e97889

Browse files
committed
[SILInliner] Only add lexical borrows when needed.
If a guaranted function argument is lexical, its lifetime must be mainted during inlining. If the caller's value is already lexical, no work is required to do the inlining.
1 parent 1b1972c commit 6e97889

File tree

1 file changed

+68
-26
lines changed

1 file changed

+68
-26
lines changed

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 68 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -305,8 +305,7 @@ class SILInlineCloner
305305
void cloneInline(ArrayRef<SILValue> AppliedArgs);
306306

307307
protected:
308-
SILValue borrowFunctionArgument(SILValue callArg, FullApplySite AI,
309-
unsigned index);
308+
SILValue borrowFunctionArgument(SILValue callArg, unsigned index);
310309

311310
void visitDebugValueInst(DebugValueInst *Inst);
312311
void visitHopToExecutorInst(HopToExecutorInst *Inst);
@@ -486,7 +485,7 @@ void SILInlineCloner::cloneInline(ArrayRef<SILValue> AppliedArgs) {
486485
} else {
487486
// Insert begin/end borrow for guaranteed arguments.
488487
if (paramInfo.isGuaranteed()) {
489-
if (SILValue newValue = borrowFunctionArgument(callArg, Apply, idx)) {
488+
if (SILValue newValue = borrowFunctionArgument(callArg, idx)) {
490489
callArg = newValue;
491490
borrowedArgs[idx] = true;
492491
}
@@ -631,34 +630,77 @@ void SILInlineCloner::postFixUp(SILFunction *calleeFunction) {
631630
deleter.forceDelete(Apply.getInstruction());
632631
}
633632

634-
SILValue SILInlineCloner::borrowFunctionArgument(SILValue callArg,
635-
FullApplySite AI,
636-
unsigned index) {
637-
auto &mod = Apply.getFunction()->getModule();
633+
namespace {
634+
635+
enum class Scope : uint8_t {
636+
None,
637+
Bare,
638+
Lexical,
639+
};
640+
Scope scopeForArgument(Scope nonlexicalScope, SILValue callArg, unsigned index,
641+
SILFunction *caller, SILFunction *callee) {
642+
if (!caller->hasOwnership()) {
643+
// The function isn't in OSSA. Borrows/moves are not meaningful.
644+
return Scope::None;
645+
}
646+
647+
auto &mod = caller->getModule();
638648
auto enableLexicalLifetimes =
639649
mod.getASTContext().SILOpts.supportsLexicalLifetimes(mod);
640-
auto argOwnershipRequiresBorrow = [&]() {
641-
auto kind = callArg->getOwnershipKind();
642-
if (enableLexicalLifetimes) {
643-
// At this point, we know that the function argument is @guaranteed.
644-
// If the value passed as that parameter has ownership, always add a
645-
// lexical borrow scope to ensure that the value stays alive for the
646-
// duration of the inlined callee.
647-
return kind != OwnershipKind::None;
648-
}
649-
return kind == OwnershipKind::Owned;
650-
};
651-
if (!AI.getFunction()->hasOwnership() || !argOwnershipRequiresBorrow()) {
652-
return SILValue();
650+
SILFunctionArgument *argument =
651+
cast<SILFunctionArgument>(callee->getEntryBlock()->getArgument(index));
652+
if (!enableLexicalLifetimes) {
653+
// Lexical lifetimes are disabled. Use the non-lexical scope:
654+
// - for borrows, do an ownership conversion.
655+
return nonlexicalScope;
653656
}
657+
if (!argument->getLifetime().isLexical()) {
658+
// The same applies if lexical lifetimes are enabled but the function
659+
// argument is not lexical. There is no lexical lifetime to maintain. Use
660+
// the non-lexical scope.
661+
return nonlexicalScope;
662+
}
663+
// Lexical lifetimes are enabled and the function argument is lexical.
664+
// During inlining, we need to ensure that the lifetime is maintained.
665+
if (callArg->isLexical()) {
666+
// The caller's value is already lexical. It will maintain the lifetime of
667+
// the argument. Just do an ownership conversion if needed.
668+
return nonlexicalScope;
669+
}
670+
// Lexical lifetimes are enabled, the function argument's lifetime is
671+
// lexical, but the caller's value is not lexical. Extra care is required to
672+
// maintain the function argument's lifetime. We need to add a lexical
673+
// scope.
674+
return Scope::Lexical;
675+
}
654676

655-
SILFunctionArgument *argument = cast<SILFunctionArgument>(
656-
getCalleeFunction()->getEntryBlock()->getArgument(index));
677+
} // anonymous namespace
657678

658-
SILBuilderWithScope beginBuilder(AI.getInstruction(), getBuilder());
659-
auto isLexical =
660-
enableLexicalLifetimes && argument->getLifetime().isLexical();
661-
return beginBuilder.createBeginBorrow(AI.getLoc(), callArg, isLexical);
679+
SILValue SILInlineCloner::borrowFunctionArgument(SILValue callArg,
680+
unsigned index) {
681+
// The "minimal" borrow scope: Guaranteed values are valid operands to some
682+
// instructions that owned values are not. If the caller's value is owned,
683+
// it must be converted (via a "bare" begin_borrow) to a guaranteed value so
684+
// that it can be used in place of the original guaranteed value in the
685+
// instructions that are being inlined.
686+
auto scopeForOwnership = callArg->getOwnershipKind() == OwnershipKind::Owned
687+
? Scope::Bare
688+
: Scope::None;
689+
auto scope = scopeForArgument(scopeForOwnership, callArg, index,
690+
Apply.getFunction(), getCalleeFunction());
691+
bool isLexical;
692+
switch (scope) {
693+
case Scope::None:
694+
return SILValue();
695+
case Scope::Bare:
696+
isLexical = false;
697+
break;
698+
case Scope::Lexical:
699+
isLexical = true;
700+
break;
701+
}
702+
SILBuilderWithScope beginBuilder(Apply.getInstruction(), getBuilder());
703+
return beginBuilder.createBeginBorrow(Apply.getLoc(), callArg, isLexical);
662704
}
663705

664706
void SILInlineCloner::visitDebugValueInst(DebugValueInst *Inst) {

0 commit comments

Comments
 (0)