Skip to content

Commit f4e1b2a

Browse files
committed
[move-only] Update SILGen/MoveCheckers so that vars are emitted in eagerly projected box form.
This is the first slice of bringing up escaping closure support. The support is based around introducing a new type of SILGen VarLoc: a VarLoc with a box and without a value. Because the VarLoc only has a box, we have to in SILGen always eagerly reproject out the address from the box. The reason why I am doing this is that it makes it easy for the move checker to distinguish in between different accesses to the box that we want to check separately. As such every time that we open the box, we insert a mark_must_check [assignable_but_not_consumable] on that project. If allocbox_to_stack manages to determine that the box can be stack allocated, we eliminate all of the mark_must_check and place a new mark_must_check [consumable_and_assignable] on the alloc_stack. The end result is that we get the old model that we had before and also can support escaping closures.
1 parent 5f7b0d0 commit f4e1b2a

18 files changed

+445
-147
lines changed

lib/SILGen/SILGenConstructor.cpp

Lines changed: 24 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -399,7 +399,11 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
399399
// Allocate the local variable for 'self'.
400400
emitLocalVariableWithCleanup(selfDecl, MUIKind)->finishInitialization(*this);
401401

402-
SILValue selfLV = VarLocs[selfDecl].value;
402+
ManagedValue selfLV =
403+
maybeEmitValueOfLocalVarDecl(selfDecl, AccessKind::ReadWrite);
404+
if (!selfLV)
405+
selfLV = maybeEmitAddressForBoxOfLocalVarDecl(selfDecl, selfDecl);
406+
assert(selfLV);
403407

404408
// Emit the prolog.
405409
emitBasicProlog(ctor->getParameters(),
@@ -491,7 +495,13 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
491495

492496
if (!F.getConventions().hasIndirectSILResults()) {
493497
// Otherwise, load and return the final 'self' value.
494-
selfValue = lowering.emitLoad(B, cleanupLoc, selfLV,
498+
if (selfLV.getType().isMoveOnly()) {
499+
selfLV = B.createMarkMustCheckInst(
500+
cleanupLoc, selfLV,
501+
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
502+
}
503+
504+
selfValue = lowering.emitLoad(B, cleanupLoc, selfLV.getValue(),
495505
LoadOwnershipQualifier::Copy);
496506

497507
// Inject the self value into an optional if the constructor is failable.
@@ -513,17 +523,16 @@ void SILGenFunction::emitValueConstructor(ConstructorDecl *ctor) {
513523
returnAddress = completeReturnAddress;
514524
} else {
515525
// If this is a failable initializer, project out the payload.
516-
returnAddress = B.createInitEnumDataAddr(cleanupLoc,
517-
completeReturnAddress,
518-
getASTContext().getOptionalSomeDecl(),
519-
selfLV->getType());
526+
returnAddress = B.createInitEnumDataAddr(
527+
cleanupLoc, completeReturnAddress,
528+
getASTContext().getOptionalSomeDecl(), selfLV.getType());
520529
}
521530

522531
// We have to do a non-take copy because someone else may be using the
523532
// box (e.g. someone could have closed over it).
524-
B.createCopyAddr(cleanupLoc, selfLV, returnAddress,
533+
B.createCopyAddr(cleanupLoc, selfLV.getLValueAddress(), returnAddress,
525534
IsNotTake, IsInitialization);
526-
535+
527536
// Inject the enum tag if the result is optional because of failability.
528537
if (ctor->isFailable()) {
529538
// Inject the 'Some' tag.
@@ -1022,14 +1031,19 @@ void SILGenFunction::emitClassConstructorInitializer(ConstructorDecl *ctor) {
10221031
static ManagedValue emitSelfForMemberInit(SILGenFunction &SGF, SILLocation loc,
10231032
VarDecl *selfDecl) {
10241033
CanType selfFormalType = selfDecl->getType()->getCanonicalType();
1025-
if (selfFormalType->hasReferenceSemantics())
1034+
if (selfFormalType->hasReferenceSemantics()) {
10261035
return SGF.emitRValueForDecl(loc, selfDecl, selfFormalType,
10271036
AccessSemantics::DirectToStorage,
10281037
SGFContext::AllowImmediatePlusZero)
10291038
.getAsSingleValue(SGF, loc);
1030-
else
1039+
} else {
1040+
// First see if we have a variable that is boxed without a value.
1041+
if (auto value = SGF.maybeEmitAddressForBoxOfLocalVarDecl(loc, selfDecl))
1042+
return value;
1043+
// Otherwise, emit the address directly.
10311044
return SGF.emitAddressOfLocalVarDecl(loc, selfDecl, selfFormalType,
10321045
SGFAccessKind::Write);
1046+
}
10331047
}
10341048

10351049
// FIXME: Can emitMemberInit() share code with InitializationForPattern in

lib/SILGen/SILGenDecl.cpp

Lines changed: 16 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -376,12 +376,8 @@ class LocalVariableInitialization : public SingleBufferInitialization {
376376
}
377377
}
378378

379-
Addr = SGF.B.createProjectBox(decl, Box, 0);
380-
if (Addr->getType().isMoveOnly()) {
381-
// TODO: Handle no implicit copy here.
382-
Addr = SGF.B.createMarkMustCheckInst(
383-
decl, Addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
384-
}
379+
if (!Box->getType().isBoxedNonCopyableType(Box->getFunction()))
380+
Addr = SGF.B.createProjectBox(decl, Box, 0);
385381

386382
// Push a cleanup to destroy the local variable. This has to be
387383
// inactive until the variable is initialized.
@@ -401,16 +397,24 @@ class LocalVariableInitialization : public SingleBufferInitialization {
401397
}
402398

403399
SILValue getAddress() const {
400+
assert(Addr);
404401
return Addr;
405402
}
406403

404+
/// If we have an address, returns the address. Otherwise, if we only have a
405+
/// box, lazily projects it out and returns it.
407406
SILValue getAddressForInPlaceInitialization(SILGenFunction &SGF,
408407
SILLocation loc) override {
408+
if (!Addr && Box) {
409+
auto pbi = SGF.B.createProjectBox(loc, Box, 0);
410+
return pbi;
411+
}
412+
409413
return getAddress();
410414
}
411415

412416
bool isInPlaceInitializationOfGlobal() const override {
413-
return isa<GlobalAddrInst>(getAddress());
417+
return dyn_cast_or_null<GlobalAddrInst>(Addr);
414418
}
415419

416420
void finishUninitialized(SILGenFunction &SGF) override {
@@ -421,7 +425,11 @@ class LocalVariableInitialization : public SingleBufferInitialization {
421425
/// Remember that this is the memory location that we've emitted the
422426
/// decl to.
423427
assert(SGF.VarLocs.count(decl) == 0 && "Already emitted the local?");
424-
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);
428+
429+
if (Addr)
430+
SGF.VarLocs[decl] = SILGenFunction::VarLoc::get(Addr, Box);
431+
else
432+
SGF.VarLocs[decl] = SILGenFunction::VarLoc::getForBox(Box);
425433

426434
SingleBufferInitialization::finishInitialization(SGF);
427435
assert(!DidFinish &&

lib/SILGen/SILGenFunction.cpp

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,8 @@ void SILGenFunction::emitCaptures(SILLocation loc,
357357

358358
// Get an address value for a SILValue if it is address only in an type
359359
// expansion context without opaque archetype substitution.
360-
auto getAddressValue = [&](SILValue entryValue) -> SILValue {
360+
auto getAddressValue = [&](VarLoc entryVarLoc) -> SILValue {
361+
SILValue entryValue = entryVarLoc.getValueOrBoxedValue(*this, vd);
361362
if (SGM.M.useLoweredAddresses()
362363
&& SGM.Types
363364
.getTypeLowering(
@@ -425,14 +426,14 @@ void SILGenFunction::emitCaptures(SILLocation loc,
425426
if (canGuarantee) {
426427
// No-escaping stored declarations are captured as the
427428
// address of the value.
428-
auto entryValue = getAddressValue(Entry.value);
429+
auto entryValue = getAddressValue(Entry);
429430
capturedArgs.push_back(ManagedValue::forBorrowedRValue(entryValue));
430431
}
431432
else if (!silConv.useLoweredAddresses()) {
432433
capturedArgs.push_back(
433434
B.createCopyValue(loc, ManagedValue::forUnmanaged(Entry.value)));
434435
} else {
435-
auto entryValue = getAddressValue(Entry.value);
436+
auto entryValue = getAddressValue(Entry);
436437
// We cannot pass a valid SILDebugVariable while creating the temp here
437438
// See rdar://60425582
438439
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
@@ -443,7 +444,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
443444
break;
444445
}
445446
case CaptureKind::StorageAddress: {
446-
auto entryValue = getAddressValue(Entry.value);
447+
auto entryValue = getAddressValue(Entry);
447448
// No-escaping stored declarations are captured as the
448449
// address of the value.
449450
assert(entryValue->getType().isAddress() && "no address for captured var!");
@@ -452,7 +453,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
452453
}
453454

454455
case CaptureKind::Box: {
455-
auto entryValue = getAddressValue(Entry.value);
456+
auto entryValue = getAddressValue(Entry);
456457
// LValues are captured as both the box owning the value and the
457458
// address of the value.
458459
assert(entryValue->getType().isAddress() && "no address for captured var!");
@@ -501,7 +502,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
501502
break;
502503
}
503504
case CaptureKind::ImmutableBox: {
504-
auto entryValue = getAddressValue(Entry.value);
505+
auto entryValue = getAddressValue(Entry);
505506
// LValues are captured as both the box owning the value and the
506507
// address of the value.
507508
assert(entryValue->getType().isAddress() &&

lib/SILGen/SILGenFunction.h

Lines changed: 36 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "swift/Basic/ProfileCounter.h"
2626
#include "swift/Basic/Statistic.h"
2727
#include "swift/SIL/SILBuilder.h"
28+
#include "swift/SIL/SILType.h"
2829
#include "llvm/ADT/PointerIntPair.h"
2930

3031
namespace swift {
@@ -394,11 +395,12 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
394395
FormalEvaluationContext FormalEvalContext;
395396

396397
/// VarLoc - representation of an emitted local variable or constant. There
397-
/// are three scenarios here:
398+
/// are four scenarios here:
398399
///
399-
/// 1) This could be a simple "var" or "let" emitted into an alloc_box. In
400-
/// this case, 'value' contains a pointer (it is always an address) to the
401-
/// value, and 'box' contains a pointer to the retain count for the box.
400+
/// 1) This could be a simple copyable "var" or "let" emitted into an
401+
/// alloc_box. In this case, 'value' contains a pointer (it is always an
402+
/// address) to the value, and 'box' contains a pointer to the retain
403+
/// count for the box.
402404
/// 2) This could be a simple non-address-only "let" represented directly. In
403405
/// this case, 'value' is the value of the let and is never of address
404406
/// type. 'box' is always nil.
@@ -407,13 +409,20 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
407409
/// incoming argument of 'in_guaranteed' convention). In this case,
408410
/// 'value' is a pointer to the memory (and thus, its type is always an
409411
/// address) and the 'box' is nil.
412+
/// 4) This could be a noncopyable "var" or "let" emitted into an
413+
/// alloc_box. In this case, 'value' is nil and the 'box' contains the box
414+
/// itself. The user must always reproject from the box and insert an
415+
/// access marker/must_must_check as appropriate.
410416
///
411-
/// Generally, code shouldn't be written to enumerate these three cases, it
417+
/// Generally, code shouldn't be written to enumerate these four cases, it
412418
/// should just handle the case of "box or not" or "address or not", depending
413419
/// on what the code cares about.
414420
struct VarLoc {
415421
/// value - the value of the variable, or the address the variable is
416422
/// stored at (if "value.getType().isAddress()" is true).
423+
///
424+
/// It may be invalid if we are supposed to lazily project out an address
425+
/// from a box.
417426
SILValue value;
418427

419428
/// box - This is the retainable box for something emitted to an alloc_box.
@@ -427,6 +436,25 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
427436
Result.box = box;
428437
return Result;
429438
}
439+
440+
static VarLoc getForBox(SILValue box) {
441+
VarLoc Result;
442+
Result.value = SILValue();
443+
Result.box = box;
444+
return Result;
445+
}
446+
447+
/// Return either the value if we have one or if we only have a box, project
448+
/// our a new box address and return that.
449+
SILValue getValueOrBoxedValue(SILGenFunction &SGF,
450+
SILLocation loc = SILLocation::invalid()) {
451+
if (value)
452+
return value;
453+
assert(box);
454+
if (loc.isNull())
455+
loc = SGF.CurrentSILLoc;
456+
return SGF.B.createProjectBox(loc, box, 0);
457+
}
430458
};
431459

432460
/// VarLocs - Entries in this map are generated when a PatternBindingDecl is
@@ -1467,6 +1495,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
14671495
ManagedValue maybeEmitValueOfLocalVarDecl(
14681496
VarDecl *var, AccessKind accessKind);
14691497

1498+
ManagedValue maybeEmitAddressForBoxOfLocalVarDecl(SILLocation loc,
1499+
VarDecl *var);
1500+
14701501
/// Produce an RValue for a reference to the specified declaration,
14711502
/// with the given type and in response to the specified expression. Try to
14721503
/// emit into the specified SGFContext to avoid copies (when provided).

0 commit comments

Comments
 (0)