Skip to content

Commit 62738bb

Browse files
committed
Implement the emission of pack expansion arguments in SILGen
Mostly fixing some existing code.
1 parent 95b8a48 commit 62738bb

File tree

13 files changed

+351
-46
lines changed

13 files changed

+351
-46
lines changed

include/swift/AST/Types.h

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

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

6715+
/// Given a type T, which must be a pack parameter, a member type
6716+
/// of a pack parameter, or a pack archetype, construct the type
6717+
/// Pack{repeat each T}.
6718+
static PackType *getSingletonPackExpansion(Type packParameter);
6719+
67066720
public:
67076721
/// Retrieves the number of elements in this pack.
67086722
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
@@ -3683,7 +3683,7 @@ class ArgEmitter {
36833683
expectedEltTy, consumed,
36843684
packAddr, formalPackType, i);
36853685
}
3686-
if (cleanup.isValid()) eltCleanups.push_back(cleanup);
3686+
if (consumed && cleanup.isValid()) eltCleanups.push_back(cleanup);
36873687
}
36883688

36893689
if (!consumed) {
@@ -3714,9 +3714,6 @@ class ArgEmitter {
37143714
SILValue packAddr,
37153715
CanPackType formalPackType,
37163716
unsigned packComponentIndex) {
3717-
auto expansionLoweredType =
3718-
expectedParamType.castTo<PackExpansionType>();
3719-
37203717
// TODO: we'll need to handle already-emitted packs for things like
37213718
// subscripts
37223719
assert(arg.isExpr() && "emitting a non-expression pack expansion");
@@ -3756,20 +3753,26 @@ class ArgEmitter {
37563753
// elements in this slice of the pack (then pop it before we exit
37573754
// this scope).
37583755

3759-
// Turn pack archetypes in the lowered pack expansion type into
3760-
// opened element archetypes. This should work fine on SIL types
3761-
// since we're not changing any interesting structure.
3762-
auto expectedLoweredElementType =
3763-
openedElementEnv->mapPackTypeIntoElementContext(
3764-
expansionLoweredType.getPatternType())->getCanonicalType();
3756+
// Turn pack archetypes in the pattern type of the lowered pack
3757+
// expansion type into opened element archetypes. These AST-level
3758+
// manipulations should work fine on SIL types since we're not
3759+
// changing any interesting structure.
3760+
SILType expectedElementType = [&] {
3761+
auto loweredPatternType =
3762+
expectedParamType.castTo<PackExpansionType>().getPatternType();
3763+
auto loweredElementType =
3764+
openedElementEnv->mapPackTypeIntoElementContext(
3765+
loweredPatternType->mapTypeOutOfContext())->getCanonicalType();
3766+
return SILType::getPrimitiveAddressType(loweredElementType);
3767+
}();
37653768

37663769
// Project the tuple element. This projection uses the
37673770
// pack expansion index because the tuple is only for the
37683771
// projection elements.
37693772
auto eltAddr =
37703773
SGF.B.createTuplePackElementAddr(expansionExpr,
37713774
packExpansionIndex, tupleAddr,
3772-
SILType::getPrimitiveAddressType(expectedLoweredElementType));
3775+
expectedElementType);
37733776
auto &eltTL = SGF.getTypeLowering(eltAddr->getType());
37743777

37753778
// 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)