Skip to content

Commit 4ae1c98

Browse files
authored
Merge pull request #65761 from slavapestov/param-pack-captures-5.9
SILGen: Wrap captures of parameter packs inside tuples [5.9]
2 parents 329c221 + 127dd95 commit 4ae1c98

File tree

9 files changed

+305
-92
lines changed

9 files changed

+305
-92
lines changed

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1929,6 +1929,16 @@ lowerCaptureContextParameters(TypeConverter &TC, SILDeclRef function,
19291929
auto type = VD->getInterfaceType();
19301930
auto canType = type->getReducedType(origGenericSig);
19311931

1932+
// If we're capturing a parameter pack, wrap it in a tuple.
1933+
if (isa<PackExpansionType>(canType)) {
1934+
assert(!cast<ParamDecl>(VD)->supportsMutation() &&
1935+
"Cannot capture a pack as an lvalue");
1936+
1937+
SmallVector<TupleTypeElt, 1> elts;
1938+
elts.push_back(canType);
1939+
canType = CanTupleType(TupleType::get(elts, TC.Context));
1940+
}
1941+
19321942
auto &loweredTL =
19331943
TC.getTypeLowering(AbstractionPattern(genericSig, canType), canType,
19341944
expansion);

lib/SIL/Verifier/SILVerifier.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -675,6 +675,7 @@ struct ImmutableAddressUseVerifier {
675675
case SILInstructionKind::TailAddrInst:
676676
case SILInstructionKind::IndexRawPointerInst:
677677
case SILInstructionKind::MarkMustCheckInst:
678+
case SILInstructionKind::PackElementGetInst:
678679
// Add these to our worklist.
679680
for (auto result : inst->getResults()) {
680681
llvm::copy(result->getUses(), std::back_inserter(worklist));
@@ -693,6 +694,25 @@ struct ImmutableAddressUseVerifier {
693694
llvm_unreachable("invoking standard assertion failure");
694695
break;
695696
}
697+
case SILInstructionKind::TuplePackElementAddrInst: {
698+
if (&cast<TuplePackElementAddrInst>(inst)->getOperandRef(
699+
TuplePackElementAddrInst::TupleOperand) == use) {
700+
for (auto result : inst->getResults()) {
701+
llvm::copy(result->getUses(), std::back_inserter(worklist));
702+
}
703+
704+
break;
705+
}
706+
707+
return false;
708+
}
709+
case SILInstructionKind::PackElementSetInst: {
710+
if (&cast<PackElementSetInst>(inst)->getOperandRef(
711+
PackElementSetInst::PackOperand) == use)
712+
return true;
713+
714+
return false;
715+
}
696716
default:
697717
llvm::errs() << "Unhandled, unexpected instruction: " << *inst;
698718
llvm_unreachable("invoking standard assertion failure");

lib/SILGen/SILGenFunction.cpp

Lines changed: 80 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -520,10 +520,24 @@ void SILGenFunction::emitCaptures(SILLocation loc,
520520
}
521521

522522
auto *vd = cast<VarDecl>(capture.getDecl());
523-
auto type = FunctionDC->mapTypeIntoContext(
524-
vd->getInterfaceType());
523+
524+
auto interfaceType = vd->getInterfaceType();
525+
526+
bool isPack = false;
527+
if (interfaceType->is<PackExpansionType>()) {
528+
assert(!vd->supportsMutation() &&
529+
"Cannot capture a pack as an lvalue");
530+
531+
SmallVector<TupleTypeElt, 1> elts;
532+
elts.push_back(interfaceType);
533+
interfaceType = TupleType::get(elts, getASTContext());
534+
535+
isPack = true;
536+
}
537+
538+
auto type = FunctionDC->mapTypeIntoContext(interfaceType);
525539
auto valueType = FunctionDC->mapTypeIntoContext(
526-
vd->getValueInterfaceType());
540+
interfaceType->getReferenceStorageReferent());
527541

528542
//
529543
// If we haven't emitted the captured value yet, we're forming a closure
@@ -586,8 +600,7 @@ void SILGenFunction::emitCaptures(SILLocation loc,
586600

587601
// Get an address value for a SILValue if it is address only in an type
588602
// expansion context without opaque archetype substitution.
589-
auto getAddressValue = [&](VarLoc entryVarLoc) -> SILValue {
590-
SILValue entryValue = entryVarLoc.value;
603+
auto getAddressValue = [&](SILValue entryValue, bool forceCopy) -> SILValue {
591604
if (SGM.M.useLoweredAddresses()
592605
&& SGM.Types
593606
.getTypeLowering(
@@ -597,32 +610,62 @@ void SILGenFunction::emitCaptures(SILLocation loc,
597610
.isAddressOnly()
598611
&& !entryValue->getType().isAddress()) {
599612

613+
assert(!isPack);
614+
600615
auto addr = emitTemporaryAllocation(vd, entryValue->getType(), false,
601616
false, /*generateDebugInfo*/ false);
602617
auto val = B.emitCopyValueOperation(loc, entryValue);
603618
auto &lowering = getTypeLowering(entryValue->getType());
604619
lowering.emitStore(B, loc, val, addr, StoreOwnershipQualifier::Init);
605-
entryValue = addr;
606-
enterDestroyCleanup(addr);
620+
621+
if (!forceCopy)
622+
enterDestroyCleanup(addr);
623+
return addr;
624+
625+
} else if (isPack) {
626+
SILType ty = getLoweredType(valueType).getObjectType();
627+
auto addr = B.createAllocStack(loc, ty);
628+
enterDeallocStackCleanup(addr);
629+
630+
auto formalPackType = cast<TupleType>(valueType->getCanonicalType())
631+
.getInducedPackType();
632+
copyPackElementsToTuple(loc, addr, entryValue, formalPackType);
633+
634+
if (!forceCopy)
635+
enterDestroyCleanup(addr);
636+
return addr;
637+
638+
} else if (forceCopy) {
639+
// We cannot pass a valid SILDebugVariable while creating the temp here
640+
// See rdar://60425582
641+
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
642+
enterDeallocStackCleanup(addr);
643+
B.createCopyAddr(loc, entryValue, addr, IsNotTake, IsInitialization);
644+
return addr;
645+
646+
} else {
647+
return entryValue;
607648
}
608-
return entryValue;
609649
};
610650

611651
auto Entry = found->second;
652+
auto val = Entry.value;
653+
612654
switch (SGM.Types.getDeclCaptureKind(capture, expansion)) {
613655
case CaptureKind::Constant: {
656+
assert(!isPack);
657+
614658
// let declarations.
615659
auto &tl = getTypeLowering(valueType);
616-
SILValue Val = Entry.value;
617660
bool eliminateMoveOnlyWrapper =
618-
Val->getType().isMoveOnlyWrapped() &&
619-
!vd->getInterfaceType()->is<SILMoveOnlyWrappedType>();
661+
val->getType().isMoveOnlyWrapped() &&
662+
!interfaceType->is<SILMoveOnlyWrappedType>();
620663

621-
if (!Val->getType().isAddress()) {
664+
if (!val->getType().isAddress()) {
622665
// Our 'let' binding can guarantee the lifetime for the callee,
623666
// if we don't need to do anything more to it.
624667
if (canGuarantee && !vd->getInterfaceType()->is<ReferenceStorageType>()) {
625-
auto guaranteed = ManagedValue::forUnmanaged(Val).borrow(*this, loc);
668+
auto guaranteed = ManagedValue::forUnmanaged(val).borrow(*this, loc);
626669
if (eliminateMoveOnlyWrapper)
627670
guaranteed = B.createGuaranteedMoveOnlyWrapperToCopyableValue(
628671
loc, guaranteed);
@@ -631,64 +674,63 @@ void SILGenFunction::emitCaptures(SILLocation loc,
631674
}
632675

633676
// Just copy a by-val let.
634-
Val = B.emitCopyValueOperation(loc, Val);
677+
val = B.emitCopyValueOperation(loc, val);
635678
// If we need to unwrap a moveonlywrapped value, do so now but in an
636679
// owned way to ensure that the partial apply is viewed as a semantic
637680
// use of the value.
638681
if (eliminateMoveOnlyWrapper)
639-
Val = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, Val);
682+
val = B.createOwnedMoveOnlyWrapperToCopyableValue(loc, val);
640683
} else {
641684
// If we have a mutable binding for a 'let', such as 'self' in an
642685
// 'init' method, load it.
643-
if (Val->getType().isMoveOnly()) {
644-
Val = B.createMarkMustCheckInst(
645-
loc, Val,
686+
if (val->getType().isMoveOnly()) {
687+
val = B.createMarkMustCheckInst(
688+
loc, val,
646689
MarkMustCheckInst::CheckKind::AssignableButNotConsumable);
647690
}
648-
Val = emitLoad(loc, Val, tl, SGFContext(), IsNotTake).forward(*this);
691+
val = emitLoad(loc, val, tl, SGFContext(), IsNotTake).forward(*this);
649692
}
650693

651694
// If we're capturing an unowned pointer by value, we will have just
652695
// loaded it into a normal retained class pointer, but we capture it as
653696
// an unowned pointer. Convert back now.
654-
if (vd->getInterfaceType()->is<ReferenceStorageType>())
655-
Val = emitConversionFromSemanticValue(loc, Val, getLoweredType(type));
697+
if (interfaceType->is<ReferenceStorageType>())
698+
val = emitConversionFromSemanticValue(loc, val, getLoweredType(type));
656699

657-
capturedArgs.push_back(emitManagedRValueWithCleanup(Val));
700+
capturedArgs.push_back(emitManagedRValueWithCleanup(val));
658701
break;
659702
}
660703
case CaptureKind::Immutable: {
661704
if (canGuarantee) {
662705
// No-escaping stored declarations are captured as the
663706
// address of the value.
664-
auto entryValue = getAddressValue(Entry);
665-
capturedArgs.push_back(ManagedValue::forBorrowedRValue(entryValue));
707+
auto addr = getAddressValue(val, /*forceCopy=*/false);
708+
capturedArgs.push_back(ManagedValue::forBorrowedRValue(addr));
666709
}
667710
else if (!silConv.useLoweredAddresses()) {
668711
capturedArgs.push_back(
669-
B.createCopyValue(loc, ManagedValue::forUnmanaged(Entry.value)));
712+
B.createCopyValue(loc, ManagedValue::forUnmanaged(val)));
670713
} else {
671-
auto entryValue = getAddressValue(Entry);
672-
// We cannot pass a valid SILDebugVariable while creating the temp here
673-
// See rdar://60425582
674-
auto addr = B.createAllocStack(loc, entryValue->getType().getObjectType());
675-
enterDeallocStackCleanup(addr);
676-
B.createCopyAddr(loc, entryValue, addr, IsNotTake, IsInitialization);
714+
auto addr = getAddressValue(val, /*forceCopy=*/true);
677715
capturedArgs.push_back(ManagedValue::forLValue(addr));
678716
}
679717
break;
680718
}
681719
case CaptureKind::StorageAddress: {
682-
auto entryValue = getAddressValue(Entry);
720+
assert(!isPack);
721+
722+
auto addr = getAddressValue(val, /*forceCopy=*/false);
683723
// No-escaping stored declarations are captured as the
684724
// address of the value.
685-
assert(entryValue->getType().isAddress() && "no address for captured var!");
686-
capturedArgs.push_back(ManagedValue::forLValue(entryValue));
725+
assert(addr->getType().isAddress() && "no address for captured var!");
726+
capturedArgs.push_back(ManagedValue::forLValue(addr));
687727
break;
688728
}
689729

690730
case CaptureKind::Box: {
691-
auto entryValue = getAddressValue(Entry);
731+
assert(!isPack);
732+
733+
auto entryValue = getAddressValue(val, /*forceCopy=*/false);
692734
// LValues are captured as both the box owning the value and the
693735
// address of the value.
694736
assert(entryValue->getType().isAddress() && "no address for captured var!");
@@ -737,7 +779,9 @@ void SILGenFunction::emitCaptures(SILLocation loc,
737779
break;
738780
}
739781
case CaptureKind::ImmutableBox: {
740-
auto entryValue = getAddressValue(Entry);
782+
assert(!isPack);
783+
784+
auto entryValue = getAddressValue(val, /*forceCopy=*/false);
741785
// LValues are captured as both the box owning the value and the
742786
// address of the value.
743787
assert(entryValue->getType().isAddress() &&

lib/SILGen/SILGenFunction.h

Lines changed: 10 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -438,24 +438,6 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
438438
Result.box = box;
439439
return Result;
440440
}
441-
442-
static VarLoc getForBox(SILValue box) {
443-
VarLoc Result;
444-
Result.value = SILValue();
445-
Result.box = box;
446-
return Result;
447-
}
448-
449-
/// Return either the value if we have one or if we only have a box, project
450-
/// our a new box address and return that.
451-
SILValue getValueOrBoxedValue(
452-
SILGenFunction &SGF,
453-
SILLocation loc = RegularLocation::getAutoGeneratedLocation()) {
454-
if (value)
455-
return value;
456-
assert(box);
457-
return SGF.B.createProjectBox(loc, box, 0);
458-
}
459441
};
460442

461443
/// VarLocs - Entries in this map are generated when a PatternBindingDecl is
@@ -2503,6 +2485,16 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
25032485
unsigned componentIndex,
25042486
SILValue currentIndexWithinComponent);
25052487

2488+
/// Copy the elements of a pack, which must consist of a single pack expansion,
2489+
/// into a tuple value having the same pack expansion and its sole element type.
2490+
void copyPackElementsToTuple(SILLocation loc, SILValue tupleAddr, SILValue pack,
2491+
CanPackType formalPackType);
2492+
2493+
/// Initialize a pack with the addresses of the elements of a tuple, which must
2494+
/// consist of a single pack expansion.
2495+
void projectTupleElementsToPack(SILLocation loc, SILValue tupleAddr, SILValue pack,
2496+
CanPackType formalPackType);
2497+
25062498
/// Return an owned managed value for \p value that is cleaned up using an end_lifetime instruction.
25072499
///
25082500
/// The end_lifetime cleanup is not placed into the ManagedValue itself and

lib/SILGen/SILGenPack.cpp

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -521,6 +521,49 @@ void SILGenFunction::emitPartialDestroyRemainingTuple(SILLocation loc,
521521
});
522522
}
523523

524+
void SILGenFunction::copyPackElementsToTuple(SILLocation loc,
525+
SILValue tupleAddr,
526+
SILValue pack,
527+
CanPackType formalPackType) {
528+
auto pair = createOpenedElementValueEnvironment(
529+
tupleAddr->getType().getTupleElementType(/*componentIndex=*/0));
530+
auto elementEnv = pair.first;
531+
auto elementTy = pair.second;
532+
533+
emitDynamicPackLoop(
534+
loc, formalPackType, /*componentIndex=*/0, elementEnv,
535+
[&](SILValue indexWithinComponent,
536+
SILValue packExpansionIndex,
537+
SILValue packIndex) {
538+
auto packEltAddr = B.createPackElementGet(
539+
loc, packIndex, pack, elementTy);
540+
auto tupleEltAddr = B.createTuplePackElementAddr(
541+
loc, packIndex, tupleAddr, elementTy);
542+
B.createCopyAddr(loc, packEltAddr, tupleEltAddr,
543+
IsNotTake, IsInitialization);
544+
});
545+
}
546+
547+
void SILGenFunction::projectTupleElementsToPack(SILLocation loc,
548+
SILValue tupleAddr,
549+
SILValue pack,
550+
CanPackType formalPackType) {
551+
auto pair = createOpenedElementValueEnvironment(
552+
tupleAddr->getType().getTupleElementType(/*componentIndex=*/0));
553+
auto elementEnv = pair.first;
554+
auto elementTy = pair.second;
555+
556+
emitDynamicPackLoop(
557+
loc, formalPackType, /*componentIndex=*/0, elementEnv,
558+
[&](SILValue indexWithinComponent,
559+
SILValue packExpansionIndex,
560+
SILValue packIndex) {
561+
auto tupleEltAddr = B.createTuplePackElementAddr(
562+
loc, packIndex, tupleAddr, elementTy);
563+
B.createPackElementSet(loc, tupleEltAddr, packIndex, pack);
564+
});
565+
}
566+
524567
void SILGenFunction::emitDynamicPackLoop(SILLocation loc,
525568
CanPackType formalPackType,
526569
unsigned componentIndex,

0 commit comments

Comments
 (0)