Skip to content

Commit 3c78a0b

Browse files
committed
[SILGen] Only lexical types get lexical lifetimes.
Only emit `begin_borrow [lexical]` and only mark `alloc_stack`s `[lexical]` when the variable in question's lifetime is lexical, not eager move.
1 parent 8d55e09 commit 3c78a0b

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

45 files changed

+261
-360
lines changed

include/swift/SIL/SILFunction.h

+7
Original file line numberDiff line numberDiff line change
@@ -1346,6 +1346,13 @@ class SILFunction
13461346
// Miscellaneous
13471347
//===--------------------------------------------------------------------===//
13481348

1349+
/// A value's lifetime, determined by looking at annotations on its decl and
1350+
/// the default lifetime for the type.
1351+
Lifetime getLifetime(VarDecl *decl, SILType ty) {
1352+
return ty.getLifetime(*this).getLifetimeForAnnotatedValue(
1353+
decl->getLifetimeAnnotation());
1354+
}
1355+
13491356
/// verify - Run the IR verifier to make sure that the SILFunction follows
13501357
/// invariants.
13511358
void verify(bool SingleFunction = true) const;

lib/SILGen/ResultPlan.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -68,9 +68,10 @@ class IndirectOpenedSelfCleanup final : public Cleanup {
6868
assert(box && "buffer never emitted before activating cleanup?!");
6969
auto theBox = box;
7070
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
71-
auto *bbi = cast<BeginBorrowInst>(theBox);
72-
SGF.B.createEndBorrow(loc, bbi);
73-
theBox = bbi->getOperand();
71+
if (auto *bbi = cast<BeginBorrowInst>(theBox)) {
72+
SGF.B.createEndBorrow(loc, bbi);
73+
theBox = bbi->getOperand();
74+
}
7475
}
7576
SGF.B.createDeallocBox(loc, theBox);
7677
}

lib/SILGen/SILGenApply.cpp

+4-3
Original file line numberDiff line numberDiff line change
@@ -3656,9 +3656,10 @@ class DeallocateUninitializedBox : public Cleanup {
36563656
void emit(SILGenFunction &SGF, CleanupLocation l, ForUnwind_t forUnwind) override {
36573657
auto theBox = box;
36583658
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
3659-
auto *bbi = cast<BeginBorrowInst>(theBox);
3660-
SGF.B.createEndBorrow(l, bbi);
3661-
theBox = bbi->getOperand();
3659+
if (auto *bbi = cast<BeginBorrowInst>(theBox)) {
3660+
SGF.B.createEndBorrow(l, bbi);
3661+
theBox = bbi->getOperand();
3662+
}
36623663
}
36633664
SGF.B.createDeallocBox(l, theBox);
36643665
}

lib/SILGen/SILGenBuilder.cpp

+9-8
Original file line numberDiff line numberDiff line change
@@ -433,16 +433,17 @@ ManagedValue SILGenBuilder::createLoadCopy(SILLocation loc, ManagedValue v,
433433
return SGF.emitManagedRValueWithCleanup(result, lowering);
434434
}
435435

436-
static ManagedValue createInputFunctionArgument(SILGenBuilder &B, SILType type,
437-
SILLocation loc,
438-
ValueDecl *decl = nullptr,
439-
bool isNoImplicitCopy = false) {
436+
static ManagedValue createInputFunctionArgument(
437+
SILGenBuilder &B, SILType type, SILLocation loc, ValueDecl *decl = nullptr,
438+
bool isNoImplicitCopy = false,
439+
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None) {
440440
auto &SGF = B.getSILGenFunction();
441441
SILFunction &F = B.getFunction();
442442
assert((F.isBare() || decl) &&
443443
"Function arguments of non-bare functions must have a decl");
444444
auto *arg = F.begin()->createFunctionArgument(type, decl);
445445
arg->setNoImplicitCopy(isNoImplicitCopy);
446+
arg->setLifetimeAnnotation(lifetimeAnnotation);
446447
switch (arg->getArgumentConvention()) {
447448
case SILArgumentConvention::Indirect_In_Guaranteed:
448449
case SILArgumentConvention::Direct_Guaranteed:
@@ -476,11 +477,11 @@ static ManagedValue createInputFunctionArgument(SILGenBuilder &B, SILType type,
476477
llvm_unreachable("bad parameter convention");
477478
}
478479

479-
ManagedValue SILGenBuilder::createInputFunctionArgument(SILType type,
480-
ValueDecl *decl,
481-
bool isNoImplicitCopy) {
480+
ManagedValue SILGenBuilder::createInputFunctionArgument(
481+
SILType type, ValueDecl *decl, bool isNoImplicitCopy,
482+
LifetimeAnnotation lifetimeAnnotation) {
482483
return ::createInputFunctionArgument(*this, type, SILLocation(decl), decl,
483-
isNoImplicitCopy);
484+
isNoImplicitCopy, lifetimeAnnotation);
484485
}
485486

486487
ManagedValue

lib/SILGen/SILGenBuilder.h

+3-2
Original file line numberDiff line numberDiff line change
@@ -226,8 +226,9 @@ class SILGenBuilder : public SILBuilder {
226226

227227
/// Create a SILArgument for an input parameter. Asserts if used to create a
228228
/// function argument for an out parameter.
229-
ManagedValue createInputFunctionArgument(SILType type, ValueDecl *decl,
230-
bool isNoImplicitCopy = false);
229+
ManagedValue createInputFunctionArgument(
230+
SILType type, ValueDecl *decl, bool isNoImplicitCopy = false,
231+
LifetimeAnnotation lifetimeAnnotation = LifetimeAnnotation::None);
231232

232233
/// Create a SILArgument for an input parameter. Uses \p loc to create any
233234
/// copies necessary. Asserts if used to create a function argument for an out

lib/SILGen/SILGenDecl.cpp

+40-16
Original file line numberDiff line numberDiff line change
@@ -299,9 +299,10 @@ class DeallocateUninitializedLocalVariable : public Cleanup {
299299
ForUnwind_t forUnwind) override {
300300
auto box = Box;
301301
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
302-
auto *bbi = cast<BeginBorrowInst>(box);
303-
SGF.B.createEndBorrow(l, bbi);
304-
box = bbi->getOperand();
302+
if (auto *bbi = dyn_cast<BeginBorrowInst>(box)) {
303+
SGF.B.createEndBorrow(l, bbi);
304+
box = bbi->getOperand();
305+
}
305306
}
306307
SGF.B.createDeallocBox(l, box);
307308
}
@@ -367,7 +368,11 @@ class LocalVariableInitialization : public SingleBufferInitialization {
367368
Box = SGF.B.createMarkUninitialized(decl, Box, kind.getValue());
368369

369370
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
370-
Box = SGF.B.createBeginBorrow(decl, Box, /*isLexical=*/true);
371+
auto loweredType = SGF.getTypeLowering(decl->getType()).getLoweredType();
372+
auto lifetime = SGF.F.getLifetime(decl, loweredType);
373+
if (lifetime.isLexical()) {
374+
Box = SGF.B.createBeginBorrow(decl, Box, /*isLexical=*/true);
375+
}
371376
}
372377

373378
Addr = SGF.B.createProjectBox(decl, Box, 0);
@@ -489,11 +494,13 @@ class LetValueInitialization : public Initialization {
489494
}
490495

491496
if (needsTemporaryBuffer) {
492-
bool isLexical =
497+
bool lexicalLifetimesEnabled =
493498
SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule());
499+
auto lifetime = SGF.F.getLifetime(vd, lowering->getLoweredType());
500+
auto isLexical = lexicalLifetimesEnabled && lifetime.isLexical();
494501
address =
495502
SGF.emitTemporaryAllocation(vd, lowering->getLoweredType(),
496-
false /*hasDynamicLifetime*/, isLexical);
503+
/*hasDynamicLifetime=*/false, isLexical);
497504
if (isUninitialized)
498505
address = SGF.B.createMarkUninitializedVar(vd, address);
499506
DestroyCleanup = SGF.enterDormantTemporaryCleanup(address, *lowering);
@@ -575,9 +582,14 @@ class LetValueInitialization : public Initialization {
575582
PrologueLoc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
576583
}
577584

578-
// Then if we don't have move only, just perform a lexical borrow.
579-
if (!SGF.getASTContext().LangOpts.Features.count(Feature::MoveOnly))
580-
return SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ true);
585+
// Then if we don't have move only, just perform a lexical borrow if the
586+
// lifetime is lexical.
587+
if (!SGF.getASTContext().LangOpts.Features.count(Feature::MoveOnly)) {
588+
if (SGF.F.getLifetime(vd, value->getType()).isLexical())
589+
return SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ true);
590+
else
591+
return value;
592+
}
581593

582594
// Otherwise, we need to perform some additional processing. First, if we
583595
// have an owned moveonly value that had a cleanup, then create a move_value
@@ -612,10 +624,14 @@ class LetValueInitialization : public Initialization {
612624
PrologueLoc, value, MarkMustCheckInst::CheckKind::NoImplicitCopy);
613625
}
614626

615-
// Otherwise, if we do not have a no implicit copy variable, just do a
616-
// borrow lexical. This is the "normal path".
617-
if (!vd->getAttrs().hasAttribute<NoImplicitCopyAttr>())
618-
return SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ true);
627+
// Otherwise, if we do not have a no implicit copy variable, just follow
628+
// the "normal path": perform a lexical borrow if the lifetime is lexical.
629+
if (!vd->getAttrs().hasAttribute<NoImplicitCopyAttr>()) {
630+
if (SGF.F.getLifetime(vd, value->getType()).isLexical())
631+
return SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ true);
632+
else
633+
return value;
634+
}
619635

620636
// If we have a no implicit copy lexical, emit the instruction stream so
621637
// that the move checker knows to check this variable.
@@ -1830,10 +1846,13 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
18301846
return;
18311847
}
18321848

1833-
auto *bbi = cast<BeginBorrowInst>(loc.box);
1834-
B.createEndBorrow(silLoc, bbi);
1835-
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
1849+
if (auto *bbi = dyn_cast<BeginBorrowInst>(loc.box)) {
1850+
B.createEndBorrow(silLoc, bbi);
1851+
B.emitDestroyValueOperation(silLoc, bbi->getOperand());
1852+
return;
1853+
}
18361854

1855+
B.emitDestroyValueOperation(silLoc, loc.box);
18371856
return;
18381857
}
18391858

@@ -1855,6 +1874,11 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
18551874
return;
18561875
}
18571876

1877+
if (!F.getLifetime(vd, Val->getType()).isLexical()) {
1878+
B.emitDestroyValueOperation(silLoc, Val);
1879+
return;
1880+
}
1881+
18581882
// This handles any case where we copy + begin_borrow or copyable_to_moveonly
18591883
// + begin_borrow. In either case we just need to end the lifetime of the
18601884
// begin_borrow's operand.

lib/SILGen/SILGenProlog.cpp

+29-13
Original file line numberDiff line numberDiff line change
@@ -58,12 +58,15 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
5858
CanSILFunctionType fnTy;
5959
ArrayRef<SILParameterInfo> &parameters;
6060
bool isNoImplicitCopy;
61+
LifetimeAnnotation lifetimeAnnotation;
6162

6263
EmitBBArguments(SILGenFunction &sgf, SILBasicBlock *parent, SILLocation l,
6364
CanSILFunctionType fnTy,
64-
ArrayRef<SILParameterInfo> &parameters, bool isNoImplicitCopy)
65+
ArrayRef<SILParameterInfo> &parameters, bool isNoImplicitCopy,
66+
LifetimeAnnotation lifetimeAnnotation)
6567
: SGF(sgf), parent(parent), loc(l), fnTy(fnTy), parameters(parameters),
66-
isNoImplicitCopy(isNoImplicitCopy) {}
68+
isNoImplicitCopy(isNoImplicitCopy),
69+
lifetimeAnnotation(lifetimeAnnotation) {}
6770

6871
ManagedValue visitType(CanType t, AbstractionPattern orig) {
6972
return visitType(t, orig, /*isInOut=*/false);
@@ -90,7 +93,8 @@ class EmitBBArguments : public CanTypeVisitor<EmitBBArguments,
9093
auto paramType =
9194
SGF.F.mapTypeIntoContext(SGF.getSILType(parameterInfo, fnTy));
9295
ManagedValue mv = SGF.B.createInputFunctionArgument(
93-
paramType, loc.getAsASTNode<ValueDecl>(), isNoImplicitCopy);
96+
paramType, loc.getAsASTNode<ValueDecl>(), isNoImplicitCopy,
97+
lifetimeAnnotation);
9498

9599
// This is a hack to deal with the fact that Self.Type comes in as a static
96100
// metatype, but we have to downcast it to a dynamic Self metatype to get
@@ -239,13 +243,14 @@ struct ArgumentInitHelper {
239243
unsigned getNumArgs() const { return ArgNo; }
240244

241245
ManagedValue makeArgument(Type ty, bool isInOut, bool isNoImplicitCopy,
242-
SILBasicBlock *parent, SILLocation l) {
246+
LifetimeAnnotation lifetime, SILBasicBlock *parent,
247+
SILLocation l) {
243248
assert(ty && "no type?!");
244249

245250
// Create an RValue by emitting destructured arguments into a basic block.
246251
CanType canTy = ty->getCanonicalType();
247252
EmitBBArguments argEmitter(SGF, parent, l, f.getLoweredFunctionType(),
248-
parameters, isNoImplicitCopy);
253+
parameters, isNoImplicitCopy, lifetime);
249254

250255
// Note: inouts of tuples are not exploded, so we bypass visit().
251256
AbstractionPattern origTy = OrigFnType
@@ -266,17 +271,24 @@ struct ArgumentInitHelper {
266271

267272
// Look for the following annotations on the function argument:
268273
// - @noImplicitCopy
274+
// - @_eagerMove
275+
// - @_lexical
269276
auto isNoImplicitCopy = pd->isNoImplicitCopy();
277+
auto lifetime = SGF.F.getLifetime(pd, value->getType());
270278

271279
// If we have a no implicit copy argument and the argument is trivial,
272280
// we need to use copyable to move only to convert it to its move only
273281
// form.
274282
if (!isNoImplicitCopy) {
275283
if (!value->getType().isMoveOnly()) {
284+
// Follow the "normal path": perform a lexical borrow if the lifetime is
285+
// lexical.
276286
if (value->getOwnershipKind() == OwnershipKind::Owned) {
277-
value =
278-
SILValue(SGF.B.createBeginBorrow(loc, value, /*isLexical*/ true));
279-
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(value);
287+
if (lifetime.isLexical()) {
288+
value = SILValue(
289+
SGF.B.createBeginBorrow(loc, value, /*isLexical*/ true));
290+
SGF.Cleanups.pushCleanup<EndBorrowCleanup>(value);
291+
}
280292
}
281293
return value;
282294
}
@@ -343,8 +355,8 @@ struct ArgumentInitHelper {
343355
SILLocation loc(pd);
344356
loc.markAsPrologue();
345357

346-
ManagedValue argrv =
347-
makeArgument(ty, pd->isInOut(), pd->isNoImplicitCopy(), parent, loc);
358+
ManagedValue argrv = makeArgument(ty, pd->isInOut(), pd->isNoImplicitCopy(),
359+
pd->getLifetimeAnnotation(), parent, loc);
348360

349361
if (pd->isInOut()) {
350362
assert(argrv.getType().isAddress() && "expected inout to be address");
@@ -362,7 +374,10 @@ struct ArgumentInitHelper {
362374
} else {
363375
if (auto *allocStack = dyn_cast<AllocStackInst>(value)) {
364376
allocStack->setArgNo(ArgNo);
365-
allocStack->setIsLexical();
377+
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(
378+
SGF.getModule()) &&
379+
SGF.F.getLifetime(pd, value->getType()).isLexical())
380+
allocStack->setIsLexical();
366381
} else {
367382
SGF.B.createDebugValueAddr(loc, value, varinfo);
368383
}
@@ -397,8 +412,9 @@ struct ArgumentInitHelper {
397412
Scope discardScope(SGF.Cleanups, CleanupLocation(PD));
398413

399414
// Manage the parameter.
400-
auto argrv = makeArgument(type, PD->isInOut(), PD->isNoImplicitCopy(),
401-
&*f.begin(), paramLoc);
415+
auto argrv =
416+
makeArgument(type, PD->isInOut(), PD->isNoImplicitCopy(),
417+
PD->getLifetimeAnnotation(), &*f.begin(), paramLoc);
402418

403419
// Emit debug information for the argument.
404420
SILLocation loc(PD);

lib/SILGen/Scope.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -60,7 +60,10 @@ static void lifetimeExtendAddressOnlyRValueSubValues(
6060
// TODO: Should these boxes that extend lifetimes for rvalue subobjects ever
6161
// be lexical?
6262
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule())) {
63-
box = SGF.B.createBeginBorrow(loc, box, /*isLexical=*/true);
63+
if (v->getType().getLifetime(SGF.F).isLexical()) {
64+
box = SGF.B.createBeginBorrow(loc, box,
65+
/*isLexical=*/true);
66+
}
6467
}
6568
SILValue addr = SGF.B.createProjectBox(loc, box, 0);
6669
SGF.B.createCopyAddr(loc, v, addr, IsTake, IsInitialization);

0 commit comments

Comments
 (0)