Skip to content

Commit ecb864c

Browse files
authored
Merge pull request #63755 from gottesmm/pr-dac78af5673ab6d4a9bebea882b8440c37c9457c
[move-only] A few small changes in preparation for a larger patch
2 parents c82189d + 969d776 commit ecb864c

25 files changed

+493
-168
lines changed

include/swift/AST/DiagnosticsSIL.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -792,6 +792,8 @@ ERROR(sil_moveonlychecker_not_understand_consumable_and_assignable, none,
792792
ERROR(sil_moveonlychecker_not_understand_moveonly, none,
793793
"Usage of a move only type that the move checker does not know how to "
794794
"check!", ())
795+
ERROR(sil_moveonlychecker_missed_copy, none,
796+
"copy of noncopyable typed value. This is a compiler bug. Please file a bug with a small example of the bug", ())
795797

796798
// move kills copyable values checker diagnostics
797799
ERROR(sil_movekillscopyablevalue_value_consumed_more_than_once, none,

include/swift/SIL/DebugUtils.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -556,13 +556,26 @@ inline DebugVarCarryingInst DebugVarCarryingInst::getFromValue(SILValue value) {
556556
return DebugVarCarryingInst();
557557
}
558558

559+
static_assert(sizeof(DebugVarCarryingInst) == sizeof(VarDeclCarryingInst) &&
560+
alignof(DebugVarCarryingInst) == alignof(VarDeclCarryingInst),
561+
"Expected debug var carrying inst to have the same "
562+
"size/alignment/layout as VarDeclCarryingInst!");
563+
559564
/// Attempt to discover a StringRef varName for the value \p value based only
560565
/// off of debug var information. If we fail, we return the name "unknown".
561566
inline StringRef getDebugVarName(SILValue value) {
562567
auto inst = DebugVarCarryingInst::getFromValue(value);
563568
return DebugVarCarryingInst::getName(inst);
564569
}
565570

571+
inline StringRef getDiagnosticName(SILValue value) {
572+
if (auto inst = DebugVarCarryingInst::getFromValue(value))
573+
return inst.getName();
574+
if (auto inst = VarDeclCarryingInst::getFromValue(value))
575+
return inst.getName();
576+
return "unknown";
577+
}
578+
566579
} // end namespace swift
567580

568581
#endif // SWIFT_SIL_DEBUGUTILS_H

include/swift/SIL/MemAccessUtils.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1254,6 +1254,8 @@ struct AccessPathWithBase {
12541254
return AccessBase(base, accessPath.getStorage().getKind());
12551255
}
12561256

1257+
bool isValid() const { return base && accessPath.isValid(); }
1258+
12571259
bool operator==(AccessPathWithBase other) const {
12581260
return accessPath == other.accessPath && base == other.base;
12591261
}

include/swift/SIL/SILBuilder.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,16 @@ class SILBuilder {
439439
ElementTypes, ElementCountOperands));
440440
}
441441

442+
/// Helper function that calls \p createAllocBox after constructing a
443+
/// SILBoxType for \p fieldType.
444+
AllocBoxInst *createAllocBox(SILLocation loc, SILType fieldType,
445+
Optional<SILDebugVariable> Var = None,
446+
bool hasDynamicLifetime = false,
447+
bool reflection = false) {
448+
return createAllocBox(loc, SILBoxType::get(fieldType.getASTType()), Var,
449+
hasDynamicLifetime, reflection);
450+
}
451+
442452
AllocBoxInst *createAllocBox(SILLocation Loc, CanSILBoxType BoxType,
443453
Optional<SILDebugVariable> Var = None,
444454
bool hasDynamicLifetime = false,

include/swift/SIL/SILType.h

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -695,7 +695,7 @@ class SILType {
695695
///
696696
/// \p field Return the type of the ith field of the box. Default set to 0
697697
/// since we only support one field today. This is just future proofing.
698-
SILType getSILBoxFieldType(const SILFunction *f, unsigned field = 0);
698+
SILType getSILBoxFieldType(const SILFunction *f, unsigned field = 0) const;
699699

700700
/// Returns the hash code for the SILType.
701701
llvm::hash_code getHashCode() const {
@@ -708,6 +708,17 @@ class SILType {
708708
SILType getSingletonAggregateFieldType(SILModule &M,
709709
ResilienceExpansion expansion) const;
710710

711+
/// \returns true if this is a SILBoxType containing a noncopyable type.
712+
bool isBoxedNonCopyableType(const SILFunction *fn) const {
713+
if (!this->is<SILBoxType>())
714+
return false;
715+
return getSILBoxFieldType(fn).isMoveOnly();
716+
}
717+
718+
bool isBoxedNonCopyableType(const SILFunction &fn) const {
719+
return isBoxedNonCopyableType(&fn);
720+
}
721+
711722
//
712723
// Accessors for types used in SIL instructions:
713724
//

include/swift/SIL/TypeLowering.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -665,6 +665,8 @@ struct SILConstantInfo {
665665
enum class CaptureKind {
666666
/// A local value captured as a mutable box.
667667
Box,
668+
/// A local value captured as an immutable box.
669+
ImmutableBox,
668670
/// A local value captured as a single pointer to storage (formed with
669671
/// @noescape closures).
670672
StorageAddress,
@@ -674,7 +676,6 @@ enum class CaptureKind {
674676
Immutable
675677
};
676678

677-
678679
/// TypeConverter - helper class for creating and managing TypeLowerings.
679680
class TypeConverter {
680681
friend class TypeLowering;

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1853,6 +1853,21 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
18531853
inputs.push_back(param);
18541854
break;
18551855
}
1856+
case CaptureKind::ImmutableBox: {
1857+
// The type in the box is lowered in the minimal context.
1858+
auto minimalLoweredTy =
1859+
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
1860+
TypeExpansionContext::minimal())
1861+
.getLoweredType();
1862+
// Lvalues are captured as a box that owns the captured value.
1863+
auto boxTy =
1864+
TC.getInterfaceBoxTypeForCapture(VD, minimalLoweredTy.getASTType(),
1865+
/*mutable*/ false);
1866+
auto convention = ParameterConvention::Direct_Guaranteed;
1867+
auto param = SILParameterInfo(boxTy, convention);
1868+
inputs.push_back(param);
1869+
break;
1870+
}
18561871
case CaptureKind::StorageAddress: {
18571872
// Non-escaping lvalues are captured as the address of the value.
18581873
SILType ty = loweredTy.getAddressType();

lib/SIL/IR/SILType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -861,7 +861,7 @@ bool SILType::isEffectivelyExhaustiveEnumType(SILFunction *f) {
861861
f->getResilienceExpansion());
862862
}
863863

864-
SILType SILType::getSILBoxFieldType(const SILFunction *f, unsigned field) {
864+
SILType SILType::getSILBoxFieldType(const SILFunction *f, unsigned field) const {
865865
auto *boxTy = getASTType()->getAs<SILBoxType>();
866866
if (!boxTy)
867867
return SILType();

lib/SIL/Utils/OwnershipUtils.cpp

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1070,7 +1070,8 @@ swift::findTransitiveUsesForAddress(SILValue projectedAddress,
10701070
isa<SwitchEnumAddrInst>(user) || isa<CheckedCastAddrBranchInst>(user) ||
10711071
isa<SelectEnumAddrInst>(user) || isa<InjectEnumAddrInst>(user) ||
10721072
isa<IsUniqueInst>(user) || isa<ValueMetatypeInst>(user) ||
1073-
isa<DebugValueInst>(user) || isa<EndBorrowInst>(user)) {
1073+
isa<DebugValueInst>(user) || isa<EndBorrowInst>(user) ||
1074+
isa<ExplicitCopyAddrInst>(user)) {
10741075
leafUse(op);
10751076
continue;
10761077
}

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -505,6 +505,15 @@ struct ImmutableAddressUseVerifier {
505505
return false;
506506
}
507507

508+
bool isConsumingOrMutatingExplicitCopyAddrUse(Operand *use) {
509+
auto *copyAddr = cast<ExplicitCopyAddrInst>(use->getUser());
510+
if (copyAddr->getDest() == use->get())
511+
return true;
512+
if (copyAddr->getSrc() == use->get() && copyAddr->isTakeOfSrc() == IsTake)
513+
return true;
514+
return false;
515+
}
516+
508517
bool isAddrCastToNonConsuming(SingleValueInstruction *i) {
509518
// Check if any of our uses are consuming. If none of them are consuming, we
510519
// are good to go.
@@ -604,6 +613,11 @@ struct ImmutableAddressUseVerifier {
604613
// mutation can happen. The checker will prove eventually that we can
605614
// convert it to a copy_addr [take] [init].
606615
break;
616+
case SILInstructionKind::ExplicitCopyAddrInst:
617+
if (isConsumingOrMutatingExplicitCopyAddrUse(use))
618+
return true;
619+
else
620+
break;
607621
case SILInstructionKind::CopyAddrInst:
608622
if (isConsumingOrMutatingCopyAddrUse(use))
609623
return true;

lib/SILGen/ManagedValue.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -364,6 +364,11 @@ class ManagedValue {
364364
return bool(getValue()) || valueAndFlag.getInt();
365365
}
366366

367+
SILFunction *getFunction() const {
368+
assert(getValue());
369+
return getValue()->getFunction();
370+
}
371+
367372
void dump() const;
368373
void dump(raw_ostream &os, unsigned indent = 0) const;
369374
void print(raw_ostream &os) const;

lib/SILGen/SILGenBuilder.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1002,3 +1002,10 @@ ManagedValue SILGenBuilder::emitCopyValueOperation(SILLocation loc,
10021002
return value;
10031003
return SGF.emitManagedRValueWithCleanup(cvi);
10041004
}
1005+
1006+
void SILGenBuilder::emitCopyAddrOperation(SILLocation loc, SILValue srcAddr,
1007+
SILValue destAddr, IsTake_t isTake,
1008+
IsInitialization_t isInitialize) {
1009+
auto &lowering = getTypeLowering(srcAddr->getType());
1010+
lowering.emitCopyInto(*this, loc, srcAddr, destAddr, isTake, isInitialize);
1011+
}

lib/SILGen/SILGenBuilder.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,10 @@ class SILGenBuilder : public SILBuilder {
449449

450450
using SILBuilder::emitCopyValueOperation;
451451
ManagedValue emitCopyValueOperation(SILLocation Loc, ManagedValue v);
452+
453+
void emitCopyAddrOperation(SILLocation loc, SILValue srcAddr,
454+
SILValue destAddr, IsTake_t isTake,
455+
IsInitialization_t isInitialize);
452456
};
453457

454458
} // namespace Lowering

lib/SILGen/SILGenFunction.cpp

Lines changed: 56 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -326,7 +326,8 @@ void SILGenFunction::emitCaptures(SILLocation loc,
326326
Diags.diagnose(capture.getLoc(), diag::value_captured_here);
327327

328328
// Emit an 'undef' of the correct type.
329-
switch (SGM.Types.getDeclCaptureKind(capture, expansion)) {
329+
auto captureKind = SGM.Types.getDeclCaptureKind(capture, expansion);
330+
switch (captureKind) {
330331
case CaptureKind::Constant:
331332
capturedArgs.push_back(emitUndef(getLoweredType(type)));
332333
break;
@@ -338,13 +339,15 @@ void SILGenFunction::emitCaptures(SILLocation loc,
338339
capturedArgs.push_back(emitUndef(ty));
339340
break;
340341
}
342+
case CaptureKind::ImmutableBox:
341343
case CaptureKind::Box: {
344+
bool isMutable = captureKind == CaptureKind::Box;
342345
auto boxTy = SGM.Types.getContextBoxTypeForCapture(
343346
vd,
344347
SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
345348
type),
346349
FunctionDC->getGenericEnvironmentOfContext(),
347-
/*mutable*/ true);
350+
/*mutable*/ isMutable);
348351
capturedArgs.push_back(emitUndef(boxTy));
349352
break;
350353
}
@@ -497,6 +500,57 @@ void SILGenFunction::emitCaptures(SILLocation loc,
497500

498501
break;
499502
}
503+
case CaptureKind::ImmutableBox: {
504+
auto entryValue = getAddressValue(Entry.value);
505+
// LValues are captured as both the box owning the value and the
506+
// address of the value.
507+
assert(entryValue->getType().isAddress() &&
508+
"no address for captured var!");
509+
// Boxes of opaque return values stay opaque.
510+
auto minimalLoweredType = SGM.Types.getLoweredRValueType(
511+
TypeExpansionContext::minimal(), type->getCanonicalType());
512+
// If this is a boxed variable, we can use it directly.
513+
if (Entry.box &&
514+
entryValue->getType().getASTType() == minimalLoweredType) {
515+
// We can guarantee our own box to the callee.
516+
if (canGuarantee) {
517+
capturedArgs.push_back(
518+
ManagedValue::forUnmanaged(Entry.box).borrow(*this, loc));
519+
} else {
520+
capturedArgs.push_back(emitManagedRetain(loc, Entry.box));
521+
}
522+
if (captureCanEscape)
523+
escapesToMark.push_back(entryValue);
524+
} else {
525+
// Address only 'let' values are passed by box. This isn't great, in
526+
// that a variable captured by multiple closures will be boxed for each
527+
// one. This could be improved by doing an "isCaptured" analysis when
528+
// emitting address-only let constants, and emit them into an alloc_box
529+
// like a variable instead of into an alloc_stack.
530+
//
531+
// TODO: This might not be profitable anymore with guaranteed captures,
532+
// since we could conceivably forward the copied value into the
533+
// closure context and pass it down to the partially applied function
534+
// in-place.
535+
// TODO: Use immutable box for immutable captures.
536+
auto boxTy = SGM.Types.getContextBoxTypeForCapture(
537+
vd, minimalLoweredType,
538+
FunctionDC->getGenericEnvironmentOfContext(),
539+
/*mutable*/ false);
540+
541+
AllocBoxInst *allocBox = B.createAllocBox(loc, boxTy);
542+
ProjectBoxInst *boxAddress = B.createProjectBox(loc, allocBox, 0);
543+
B.createCopyAddr(loc, entryValue, boxAddress, IsNotTake,
544+
IsInitialization);
545+
if (canGuarantee)
546+
capturedArgs.push_back(
547+
emitManagedRValueWithCleanup(allocBox).borrow(*this, loc));
548+
else
549+
capturedArgs.push_back(emitManagedRValueWithCleanup(allocBox));
550+
}
551+
552+
break;
553+
}
500554
}
501555
}
502556

lib/SILGen/SILGenProlog.cpp

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -517,7 +517,8 @@ static void emitCaptureArguments(SILGenFunction &SGF,
517517
};
518518

519519
auto expansion = SGF.getTypeExpansionContext();
520-
switch (SGF.SGM.Types.getDeclCaptureKind(capture, expansion)) {
520+
auto captureKind = SGF.SGM.Types.getDeclCaptureKind(capture, expansion);
521+
switch (captureKind) {
521522
case CaptureKind::Constant: {
522523
auto type = getVarTypeInCaptureContext();
523524
auto &lowering = SGF.getTypeLowering(type);
@@ -569,24 +570,31 @@ static void emitCaptureArguments(SILGenFunction &SGF,
569570
break;
570571
}
571572

573+
case CaptureKind::ImmutableBox:
572574
case CaptureKind::Box: {
573575
// LValues are captured as a retained @box that owns
574576
// the captured value.
575577
auto type = getVarTypeInCaptureContext();
576578
// Get the content for the box in the minimal resilience domain because we
577579
// are declaring a type.
580+
bool isMutable = captureKind != CaptureKind::ImmutableBox;
578581
auto boxTy = SGF.SGM.Types.getContextBoxTypeForCapture(
579582
VD,
580583
SGF.SGM.Types.getLoweredRValueType(TypeExpansionContext::minimal(),
581584
type),
582-
SGF.F.getGenericEnvironment(), /*mutable*/ true);
585+
SGF.F.getGenericEnvironment(), /*mutable*/ isMutable);
583586
auto *box = SGF.F.begin()->createFunctionArgument(
584587
SILType::getPrimitiveObjectType(boxTy), VD);
585588
box->setClosureCapture(true);
586589
SILValue addr = SGF.B.createProjectBox(VD, box, 0);
587-
if (addr->getType().isMoveOnly())
588-
addr = SGF.B.createMarkMustCheckInst(
589-
VD, addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
590+
if (addr->getType().isMoveOnly()) {
591+
if (isMutable)
592+
addr = SGF.B.createMarkMustCheckInst(
593+
VD, addr, MarkMustCheckInst::CheckKind::ConsumableAndAssignable);
594+
else
595+
addr = SGF.B.createMarkMustCheckInst(
596+
VD, addr, MarkMustCheckInst::CheckKind::NoConsumeOrAssign);
597+
}
590598
SGF.VarLocs[VD] = SILGenFunction::VarLoc::get(addr, box);
591599
SILDebugVariable DbgVar(VD->isLet(), ArgNo);
592600
SGF.B.createDebugValueAddr(Loc, addr, DbgVar);

0 commit comments

Comments
 (0)