Skip to content

Commit b3b90a8

Browse files
authored
Merge pull request #64048 from rjmccall/variadic-pack-expansion-arguments
Implement the emission of pack expansion arguments in SILGen
2 parents 5ef0c4e + 06a7468 commit b3b90a8

File tree

13 files changed

+349
-46
lines changed

13 files changed

+349
-46
lines changed

include/swift/AST/Types.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -753,6 +753,15 @@ class alignas(1 << TypeAlignInBits) TypeBase
753753
/// Return the root generic parameter of this type parameter type.
754754
GenericTypeParamType *getRootGenericParam();
755755

756+
/// Given that this type is the result of substituting a pack parameter,
757+
/// return it as a the pack type. We want to have a representational
758+
/// invariant that these substitutions always produce PackTypes; when
759+
/// that's in place, we can replace all uses of this function with
760+
/// `->castTo<PackType>()`. In the meantime, it's permitted for these
761+
/// substitutions to be unadorned pack parameters or archetypes, which
762+
/// this function will wrap into a pack containing a singleton expansion.
763+
PackType *getPackSubstitutionAsPackType();
764+
756765
/// Determines whether this type is an lvalue. This includes both straight
757766
/// lvalue types as well as tuples or optionals of lvalues.
758767
bool hasLValueType() {
@@ -6732,6 +6741,11 @@ class PackType final : public TypeBase, public llvm::FoldingSetNode,
67326741
TypeArrayView<GenericTypeParamType> params,
67336742
ArrayRef<Type> args);
67346743

6744+
/// Given a type T, which must be a pack parameter, a member type
6745+
/// of a pack parameter, or a pack archetype, construct the type
6746+
/// Pack{repeat each T}.
6747+
static PackType *getSingletonPackExpansion(Type packParameter);
6748+
67356749
public:
67366750
/// Retrieves the number of elements in this pack.
67376751
unsigned getNumElements() const { return Bits.PackType.Count; }

lib/AST/ASTContext.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3302,6 +3302,11 @@ PackType *PackType::getEmpty(const ASTContext &C) {
33023302
return cast<PackType>(CanType(C.TheEmptyPackType));
33033303
}
33043304

3305+
PackType *PackType::getSingletonPackExpansion(Type param) {
3306+
assert(param->isParameterPack() || param->is<PackArchetypeType>());
3307+
return get(param->getASTContext(), {PackExpansionType::get(param, param)});
3308+
}
3309+
33053310
CanPackType CanPackType::get(const ASTContext &C, ArrayRef<CanType> elements) {
33063311
SmallVector<Type, 8> ncElements(elements.begin(), elements.end());
33073312
return CanPackType(PackType::get(C, ncElements));

lib/AST/GenericEnvironment.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ void GenericEnvironment::forEachPackElementBinding(
177177
auto *elementArchetype =
178178
mapTypeIntoContext(*elementIt++)->castTo<ElementArchetypeType>();
179179
auto *packSubstitution = maybeApplyOuterContextSubstitutions(genericParam)
180-
->template castTo<PackType>();
180+
->getPackSubstitutionAsPackType();
181181
function(elementArchetype, packSubstitution);
182182
});
183183

lib/AST/ParameterPack.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -86,6 +86,14 @@ bool GenericTypeParamType::isParameterPack() const {
8686
GenericTypeParamType::TYPE_SEQUENCE_BIT;
8787
}
8888

89+
PackType *TypeBase::getPackSubstitutionAsPackType() {
90+
if (auto pack = getAs<PackType>()) {
91+
return pack;
92+
} else {
93+
return PackType::getSingletonPackExpansion(this);
94+
}
95+
}
96+
8997
/// G<{X1, ..., Xn}, {Y1, ..., Yn}>... => {G<X1, Y1>, ..., G<Xn, Yn>}...
9098
PackExpansionType *PackExpansionType::expand() {
9199
auto countType = getCountType();

lib/AST/Type.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -729,6 +729,11 @@ static bool isLegalFormalType(CanType type) {
729729
return isLegalFormalType(objectType);
730730
}
731731

732+
// Expansions are legal if their pattern type is legal.
733+
if (auto expansionType = dyn_cast<PackExpansionType>(type)) {
734+
return isLegalFormalType(expansionType.getPatternType());
735+
}
736+
732737
return true;
733738
}
734739

lib/SIL/IR/TypeLowering.cpp

Lines changed: 19 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -331,11 +331,13 @@ namespace {
331331
RetTy visitPackExpansionType(CanPackExpansionType type,
332332
AbstractionPattern origType,
333333
IsTypeExpansionSensitive_t isSensitive) {
334-
return asImpl().handleAddressOnly(type, {IsNotTrivial, IsFixedABI,
335-
IsAddressOnly, IsNotResilient,
336-
isSensitive,
337-
DoesNotHaveRawPointer,
338-
IsLexical});
334+
RecursiveProperties props;
335+
props.setAddressOnly();
336+
props.addSubobject(classifyType(origType.getPackExpansionPatternType(),
337+
type.getPatternType(),
338+
TC, Expansion));
339+
props = mergeIsTypeExpansionSensitive(isSensitive, props);
340+
return asImpl().handleAddressOnly(type, props);
339341
}
340342

341343
RetTy visitBuiltinRawPointerType(CanBuiltinRawPointerType type,
@@ -2193,18 +2195,20 @@ namespace {
21932195
TypeLowering *visitPackType(CanPackType packType,
21942196
AbstractionPattern origType,
21952197
IsTypeExpansionSensitive_t isSensitive) {
2196-
RecursiveProperties properties;
2197-
properties.setAddressOnly();
2198-
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
2199-
2200-
return handleAddressOnly(packType, properties);
2198+
llvm_unreachable("shouldn't get here with an unlowered type");
22012199
}
22022200

22032201
TypeLowering *visitSILPackType(CanSILPackType packType,
22042202
AbstractionPattern origType,
22052203
IsTypeExpansionSensitive_t isSensitive) {
22062204
RecursiveProperties properties;
22072205
properties.setAddressOnly();
2206+
for (auto i : indices(packType.getElementTypes())) {
2207+
auto &eltLowering =
2208+
TC.getTypeLowering(packType->getSILElementType(i),
2209+
Expansion);
2210+
properties.addSubobject(eltLowering.getRecursiveProperties());
2211+
}
22082212
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
22092213

22102214
return handleAddressOnly(packType, properties);
@@ -2215,6 +2219,11 @@ namespace {
22152219
IsTypeExpansionSensitive_t isSensitive) {
22162220
RecursiveProperties properties;
22172221
properties.setAddressOnly();
2222+
auto &patternLowering =
2223+
TC.getTypeLowering(origType.getPackExpansionPatternType(),
2224+
packExpansionType.getPatternType(),
2225+
Expansion);
2226+
properties.addSubobject(patternLowering.getRecursiveProperties());
22182227
properties = mergeIsTypeExpansionSensitive(isSensitive, properties);
22192228

22202229
return handleAddressOnly(packExpansionType, properties);

lib/SILGen/SILGenApply.cpp

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -3757,7 +3757,7 @@ class ArgEmitter {
37573757
expectedEltTy, consumed,
37583758
packAddr, formalPackType, i);
37593759
}
3760-
if (cleanup.isValid()) eltCleanups.push_back(cleanup);
3760+
if (consumed && cleanup.isValid()) eltCleanups.push_back(cleanup);
37613761
}
37623762

37633763
if (!consumed) {
@@ -3788,9 +3788,6 @@ class ArgEmitter {
37883788
SILValue packAddr,
37893789
CanPackType formalPackType,
37903790
unsigned packComponentIndex) {
3791-
auto expansionLoweredType =
3792-
expectedParamType.castTo<PackExpansionType>();
3793-
37943791
// TODO: we'll need to handle already-emitted packs for things like
37953792
// subscripts
37963793
assert(arg.isExpr() && "emitting a non-expression pack expansion");
@@ -3830,20 +3827,26 @@ class ArgEmitter {
38303827
// elements in this slice of the pack (then pop it before we exit
38313828
// this scope).
38323829

3833-
// Turn pack archetypes in the lowered pack expansion type into
3834-
// opened element archetypes. This should work fine on SIL types
3835-
// since we're not changing any interesting structure.
3836-
auto expectedLoweredElementType =
3837-
openedElementEnv->mapPackTypeIntoElementContext(
3838-
expansionLoweredType.getPatternType())->getCanonicalType();
3830+
// Turn pack archetypes in the pattern type of the lowered pack
3831+
// expansion type into opened element archetypes. These AST-level
3832+
// manipulations should work fine on SIL types since we're not
3833+
// changing any interesting structure.
3834+
SILType expectedElementType = [&] {
3835+
auto loweredPatternType =
3836+
expectedParamType.castTo<PackExpansionType>().getPatternType();
3837+
auto loweredElementType =
3838+
openedElementEnv->mapPackTypeIntoElementContext(
3839+
loweredPatternType->mapTypeOutOfContext())->getCanonicalType();
3840+
return SILType::getPrimitiveAddressType(loweredElementType);
3841+
}();
38393842

38403843
// Project the tuple element. This projection uses the
38413844
// pack expansion index because the tuple is only for the
38423845
// projection elements.
38433846
auto eltAddr =
38443847
SGF.B.createTuplePackElementAddr(expansionExpr,
38453848
packExpansionIndex, tupleAddr,
3846-
SILType::getPrimitiveAddressType(expectedLoweredElementType));
3849+
expectedElementType);
38473850
auto &eltTL = SGF.getTypeLowering(eltAddr->getType());
38483851

38493852
// Evaluate the pattern expression into that address.

lib/SILGen/SILGenBuilder.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -475,9 +475,11 @@ static ManagedValue createInputFunctionArgument(
475475
return ManagedValue::forUnmanaged(arg).copy(SGF, loc);
476476

477477
case SILArgumentConvention::Direct_Owned:
478-
case SILArgumentConvention::Pack_Owned:
479478
return SGF.emitManagedRValueWithCleanup(arg);
480479

480+
case SILArgumentConvention::Pack_Owned:
481+
return SGF.emitManagedPackWithCleanup(arg);
482+
481483
case SILArgumentConvention::Indirect_In:
482484
if (SGF.silConv.useLoweredAddresses())
483485
return SGF.emitManagedBufferWithCleanup(arg);

lib/SILGen/SILGenExpr.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1531,7 +1531,14 @@ RValueEmitter::visitPackExpansionExpr(PackExpansionExpr *E,
15311531

15321532
RValue
15331533
RValueEmitter::visitPackElementExpr(PackElementExpr *E, SGFContext C) {
1534-
llvm_unreachable("not implemented for PackElementExpr");
1534+
FormalEvaluationScope scope(SGF);
1535+
1536+
LValue lv = SGF.emitLValue(E, SGFAccessKind::OwnedObjectRead);
1537+
1538+
// Otherwise, we can't load at +0 without further analysis, since the formal
1539+
// access into the lvalue will end immediately.
1540+
return SGF.emitLoadOfLValue(E, std::move(lv),
1541+
C.withFollowingSideEffects());
15351542
}
15361543

15371544
RValue

lib/SILGen/SILGenFunction.h

Lines changed: 24 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,14 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
559559
/// points.
560560
SILValue ExpectedExecutor;
561561

562+
/// The pack index value for the innermost pack expansion.
563+
SILValue InnermostPackIndex;
564+
565+
SILValue getInnermostPackIndex() const {
566+
assert(InnermostPackIndex && "not inside a pack expansion!");
567+
return InnermostPackIndex;
568+
}
569+
562570
/// True if 'return' without an operand or falling off the end of the current
563571
/// function is valid.
564572
bool allowsVoidReturn() const { return ReturnDest.getBlock()->args_empty(); }
@@ -1666,6 +1674,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
16661674
ManagedValue emitManagedBufferWithCleanup(SILValue addr,
16671675
const TypeLowering &lowering);
16681676

1677+
ManagedValue emitManagedPackWithCleanup(SILValue addr,
1678+
CanPackType formalPackType
1679+
= CanPackType());
1680+
16691681
ManagedValue emitFormalAccessManagedRValueWithCleanup(SILLocation loc,
16701682
SILValue value);
16711683
ManagedValue emitFormalAccessManagedBufferWithCleanup(SILLocation loc,
@@ -2490,14 +2502,18 @@ class LLVM_LIBRARY_VISIBILITY SILGenFunction
24902502
/// starting at index limitWithinComponent - 1
24912503
/// \param emitBody - a function that will be called to emit the body of
24922504
/// the loop. It's okay if this has paths that exit the body of the loop,
2493-
/// but it should leave the insertion point set at the end. Will be
2494-
/// called within a cleanups scope. The first parameter is the current
2495-
/// index within the expansion component, a value of type Builtin.Word.
2496-
/// The second parameter is that index as a pack indexing instruction
2497-
/// that indexes into packs with the shape of the pack expasion.
2498-
/// The third parameter is the current pack index within the overall
2499-
/// pack, a pack indexing instruction that indexes into packs with the
2500-
/// shape of formalPackType.
2505+
/// but it should leave the insertion point set at the end.
2506+
///
2507+
/// The first parameter is the current index within the expansion
2508+
/// component, a value of type Builtin.Word. The second parameter is
2509+
/// that index as a pack indexing instruction that indexes into packs
2510+
/// with the shape of the pack expasion. The third parameter is the
2511+
/// current pack index within the overall pack, a pack indexing instruction
2512+
/// that indexes into packs with the shape of formalPackType.
2513+
///
2514+
/// This function will be called within a cleanups scope and with
2515+
/// InnermostPackIndex set to the pack expansion index value (the
2516+
/// second parameter).
25012517
void emitDynamicPackLoop(SILLocation loc,
25022518
CanPackType formalPackType,
25032519
unsigned componentIndex,

lib/SILGen/SILGenLValue.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -309,6 +309,8 @@ class LLVM_LIBRARY_VISIBILITY SILGenLValue
309309
LValueOptions options);
310310
LValue visitOpaqueValueExpr(OpaqueValueExpr *e, SGFAccessKind accessKind,
311311
LValueOptions options);
312+
LValue visitPackElementExpr(PackElementExpr *e, SGFAccessKind accessKind,
313+
LValueOptions options);
312314

313315
// Nodes that make up components of lvalue paths
314316

@@ -3313,6 +3315,42 @@ LValue SILGenLValue::visitOpaqueValueExpr(OpaqueValueExpr *e,
33133315
return lv;
33143316
}
33153317

3318+
LValue SILGenLValue::visitPackElementExpr(PackElementExpr *e,
3319+
SGFAccessKind accessKind,
3320+
LValueOptions options) {
3321+
auto refExpr = e->getPackRefExpr();
3322+
3323+
auto substFormalType = e->getType()->getCanonicalType();
3324+
3325+
if (auto declRefExpr = dyn_cast<DeclRefExpr>(refExpr)) {
3326+
if (auto var = dyn_cast<VarDecl>(declRefExpr->getDecl())) {
3327+
auto origFormalType = SGF.SGM.Types.getAbstractionPattern(var);
3328+
auto elementTy =
3329+
SGF.getLoweredType(origFormalType, substFormalType).getAddressType();
3330+
SILValue packAddr =
3331+
SGF.emitAddressOfLocalVarDecl(declRefExpr, var,
3332+
substFormalType,
3333+
accessKind)
3334+
.getLValueAddress();
3335+
auto packIndex = SGF.getInnermostPackIndex();
3336+
auto elementAddr =
3337+
SGF.B.createPackElementGet(e, packIndex, packAddr, elementTy);
3338+
return LValue::forAddress(accessKind,
3339+
ManagedValue::forLValue(elementAddr),
3340+
/*access enforcement*/ None,
3341+
origFormalType, substFormalType);
3342+
}
3343+
}
3344+
3345+
SGF.SGM.diagnose(refExpr, diag::not_implemented,
3346+
"emission of 'each' for this kind of expression");
3347+
auto loweredTy = SGF.getLoweredType(substFormalType).getAddressType();
3348+
auto fakeAddr = ManagedValue::forLValue(SILUndef::get(loweredTy, SGF.F));
3349+
return LValue::forAddress(accessKind, fakeAddr, /*access enforcement*/ None,
3350+
AbstractionPattern(substFormalType),
3351+
substFormalType);
3352+
}
3353+
33163354
LValue SILGenLValue::visitDotSyntaxBaseIgnoredExpr(DotSyntaxBaseIgnoredExpr *e,
33173355
SGFAccessKind accessKind,
33183356
LValueOptions options) {

0 commit comments

Comments
 (0)