Skip to content

Commit 912a4a8

Browse files
authored
Merge pull request swiftlang#63557 from rjmccall/variadic-generic-sil-subst
Test that SIL inlining works for the new variadic generics instructions
2 parents 5523c56 + 2169743 commit 912a4a8

File tree

6 files changed

+300
-38
lines changed

6 files changed

+300
-38
lines changed

include/swift/AST/SubstitutionMap.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ class SubstitutionMap {
169169
bool isCanonical() const;
170170

171171
/// Return the canonical form of this substitution map.
172-
SubstitutionMap getCanonical() const;
172+
SubstitutionMap getCanonical(bool canonicalizeSignature = true) const;
173173

174174
/// Apply a substitution to all replacement types in the map. Does not
175175
/// change keys.

include/swift/SIL/SILCloner.h

Lines changed: 87 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -204,7 +204,8 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
204204
}
205205
}
206206

207-
return asImpl().remapSubstitutionMap(Subs).getCanonical();
207+
return asImpl().remapSubstitutionMap(Subs)
208+
.getCanonical(/*canonicalizeSignature*/false);
208209
}
209210

210211
SILType getTypeInClonedContext(SILType Ty) {
@@ -261,14 +262,82 @@ class SILCloner : protected SILInstructionVisitor<ImplClass> {
261262
if (auto origExpansionType =
262263
dyn_cast<PackExpansionType>(origComponentType)) {
263264
auto newShapeClass = getOpASTType(origExpansionType.getCountType());
264-
newIndex += cast<PackType>(newShapeClass)->getNumElements();
265+
if (auto newShapePack = dyn_cast<PackType>(newShapeClass))
266+
newIndex += newShapePack->getNumElements();
267+
else
268+
newIndex++;
265269
} else {
266270
newIndex++;
267271
}
268272
}
269273
return newIndex;
270274
}
271275

276+
/// Does type substitution make the given tuple type no longer a tuple?
277+
bool doesOpTupleDisappear(CanTupleType type) {
278+
// Fast-path the empty tuple.
279+
if (type->getNumElements() == 0) return false;
280+
281+
// Do a first pass over the tuple elements to check out the
282+
// non-expansions. If there's more than one of them, or any of them
283+
// is labeled, we definitely stay a tuple and don't need to substitute
284+
// any of the expansions.
285+
unsigned numScalarElements = 0;
286+
for (auto index : indices(type->getElements())) {
287+
auto eltType = type.getElementType(index);
288+
// Ignore pack expansions in this pass.
289+
if (isa<PackExpansionType>(eltType)) continue;
290+
291+
// If there's a labeled scalar element, we'll stay a tuple.
292+
if (type->getElement(index).hasName()) return false;
293+
294+
// If there are multiple scalar elements, we'll stay a tuple.
295+
if (++numScalarElements > 1) return false;
296+
}
297+
298+
assert(numScalarElements <= 1);
299+
300+
// We must have expansions if we got here: if all the elements were
301+
// scalar, and none of them were labelled, and there wasn't more than
302+
// one of them, and there was at least one of them, then somehow
303+
// we had a tuple with a single unlabeled element.
304+
305+
// Okay, we need to substitute the count types for the expansions.
306+
for (auto index : indices(type->getElements())) {
307+
// Ignore non-expansions because we've already counted them.
308+
auto expansion = dyn_cast<PackExpansionType>(type.getElementType(index));
309+
if (!expansion) continue;
310+
311+
// Substitute the shape class of the expansion.
312+
auto newShapeClass = getOpASTType(expansion.getCountType());
313+
auto newShapePack = dyn_cast<PackType>(newShapeClass);
314+
315+
// If the element has a name, then the tuple sticks around unless
316+
// the expansion disappears completely.
317+
if (type->getElement(index).hasName()) {
318+
if (newShapePack && newShapePack->getNumElements() == 0)
319+
continue;
320+
return false;
321+
}
322+
323+
// Otherwise, walk the substituted shape components.
324+
for (auto newShapeElement : newShapePack.getElementTypes()) {
325+
// If there's an expansion in the shape, we'll have an expansion
326+
// in the tuple elements, which forces the tuple structure to remain.
327+
if (isa<PackExpansionType>(newShapeElement)) return false;
328+
329+
// Otherwise, add another scalar element.
330+
if (++numScalarElements > 1) return false;
331+
}
332+
}
333+
334+
// All of the packs expanded to scalars. We should've short-circuited
335+
// if we ever saw a second or labeled scalar, so all we need to test
336+
// is whether we have exactly one scalar.
337+
assert(numScalarElements <= 1);
338+
return numScalarElements == 1;
339+
}
340+
272341
void remapRootOpenedType(CanOpenedArchetypeType archetypeTy) {
273342
assert(archetypeTy->isRoot());
274343

@@ -2492,13 +2561,15 @@ void SILCloner<ImplClass>::visitOpenPackElementInst(
24922561
auto newContextSubs =
24932562
getOpSubstitutionMap(origEnv->getPackElementContextSubstitutions());
24942563

2495-
// Substitute the shape class.
2496-
auto newShapeClass = getOpASTType(origEnv->getOpenedElementShapeClass());
2564+
// The opened shape class is a parameter of the original signature,
2565+
// which is unchanged.
2566+
auto openedShapeClass = origEnv->getOpenedElementShapeClass();
24972567

24982568
// Build the new environment.
24992569
auto newEnv =
25002570
GenericEnvironment::forOpenedElement(origEnv->getGenericSignature(),
2501-
UUID::fromTime(), newShapeClass,
2571+
UUID::fromTime(),
2572+
openedShapeClass,
25022573
newContextSubs);
25032574

25042575
// Associate the old opened archetypes with the new ones.
@@ -2552,8 +2623,17 @@ void SILCloner<ImplClass>::visitTuplePackElementAddrInst(
25522623
auto newIndex = getOpValue(Inst->getIndex());
25532624
auto newTuple = getOpValue(Inst->getTuple());
25542625
auto newElementType = getOpType(Inst->getElementType());
2555-
// FIXME: do we need to rewrite when substitution removes the
2556-
// tuple-ness of the type? If so, what do we rewrite to?
2626+
2627+
// If the tuple-ness of the operand disappears due to substitution,
2628+
// replace this instruction with an unchecked_addr_cast.
2629+
// FIXME: use type_refine_addr instead
2630+
if (doesOpTupleDisappear(Inst->getTupleType())) {
2631+
recordClonedInstruction(
2632+
Inst, getBuilder().createUncheckedAddrCast(loc, newTuple,
2633+
newElementType));
2634+
return;
2635+
}
2636+
25572637
recordClonedInstruction(
25582638
Inst, getBuilder().createTuplePackElementAddr(loc, newIndex, newTuple,
25592639
newElementType));

lib/AST/SubstitutionMap.cpp

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -164,10 +164,12 @@ bool SubstitutionMap::isCanonical() const {
164164
return true;
165165
}
166166

167-
SubstitutionMap SubstitutionMap::getCanonical() const {
167+
SubstitutionMap SubstitutionMap::getCanonical(bool canonicalizeSignature) const {
168168
if (empty()) return *this;
169169

170-
auto canonicalSig = getGenericSignature().getCanonicalSignature();
170+
auto sig = getGenericSignature();
171+
if (canonicalizeSignature) sig = sig.getCanonicalSignature();
172+
171173
SmallVector<Type, 4> replacementTypes;
172174
for (Type replacementType : getReplacementTypesBuffer()) {
173175
if (replacementType)
@@ -181,12 +183,11 @@ SubstitutionMap SubstitutionMap::getCanonical() const {
181183
conformances.push_back(conf.getCanonicalConformanceRef());
182184
}
183185

184-
return SubstitutionMap::get(canonicalSig,
186+
return SubstitutionMap::get(sig,
185187
ArrayRef<Type>(replacementTypes),
186188
ArrayRef<ProtocolConformanceRef>(conformances));
187189
}
188190

189-
190191
SubstitutionMap SubstitutionMap::get(GenericSignature genericSig,
191192
SubstitutionMap substitutions) {
192193
if (!genericSig) {

lib/AST/Type.cpp

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -646,6 +646,21 @@ void TypeBase::getTypeVariables(
646646
}
647647
}
648648

649+
static bool isLegalSILType(CanType type);
650+
651+
static bool isLegalSILTypeOrPackExpansion(CanType type) {
652+
// Pack expansions aren't legal in arbitrary positions in SIL;
653+
// for example, we should never see a function parameter or result
654+
// of pack-expansion type. But they're allowed within SILPackTypes
655+
// and SIL TupleTypes as long as their pattern types are legal.
656+
// The count type should always be an AST type.
657+
if (auto packExpansionType = dyn_cast<PackExpansionType>(type)) {
658+
return isLegalSILType(packExpansionType.getPatternType());
659+
}
660+
661+
return isLegalSILType(type);
662+
}
663+
649664
static bool isLegalSILType(CanType type) {
650665
// L-values and inouts are not legal.
651666
if (!type->isMaterializable()) return false;
@@ -660,20 +675,14 @@ static bool isLegalSILType(CanType type) {
660675
// Tuples are legal if all their elements are legal.
661676
if (auto tupleType = dyn_cast<TupleType>(type)) {
662677
for (auto eltType : tupleType.getElementTypes()) {
663-
if (!isLegalSILType(eltType)) return false;
678+
if (!isLegalSILTypeOrPackExpansion(eltType)) return false;
664679
}
665680
return true;
666681
}
667682

668683
// Packs must be lowered.
669684
if (isa<PackType>(type)) return false;
670685

671-
// Pack expansions are legal if all their pattern and count types are legal.
672-
if (auto packExpansionType = dyn_cast<PackExpansionType>(type)) {
673-
return (isLegalSILType(packExpansionType.getPatternType()) &&
674-
isLegalSILType(packExpansionType.getCountType()));
675-
}
676-
677686
// Optionals are legal if their object type is legal.
678687
if (auto objectType = type.getOptionalObjectType()) {
679688
return isLegalSILType(objectType);

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 82 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3929,10 +3929,23 @@ class SILTypeSubstituter :
39293929
CanGenericSignature Sig;
39303930

39313931
struct PackExpansion {
3932-
CanType ExpandedShape;
3932+
/// The shape class of pack parameters that are expanded by this
3933+
/// expansion. Set during construction and not changed.
3934+
CanType OrigShapeClass;
3935+
3936+
/// The count type of the pack expansion in the current lane of
3937+
/// expansion, if any. Pack elements in this lane should be
3938+
/// expansions with this shape.
3939+
CanType SubstPackExpansionCount;
3940+
3941+
/// The index of the current lane of expansion. Basic
3942+
/// substitution of pack parameters with the same shape as
3943+
/// OrigShapeClass should yield a pack, and lanewise
3944+
/// substitution should produce this element of that pack.
39333945
unsigned Index;
39343946

3935-
PackExpansion(CanType shape) : ExpandedShape(shape), Index(0) {}
3947+
PackExpansion(CanType origShapeClass)
3948+
: OrigShapeClass(origShapeClass), Index(0) {}
39363949
};
39373950
SmallVector<PackExpansion> ActivePackExpansions;
39383951

@@ -4253,7 +4266,7 @@ class SILTypeSubstituter :
42534266

42544267
CanType visitPackExpansionType(CanPackExpansionType origType) {
42554268
CanType patternType = visit(origType.getPatternType());
4256-
CanType countType = visit(origType.getCountType());
4269+
CanType countType = substASTType(origType.getCountType());
42574270

42584271
return CanType(PackExpansionType::get(patternType, countType));
42594272
}
@@ -4264,21 +4277,24 @@ class SILTypeSubstituter :
42644277
CanType origPatternType = origType.getPatternType();
42654278

42664279
// Substitute the count type (as an AST type).
4267-
CanType substCountType = visitType(origCountType);
4280+
CanType substCountType = substASTType(origCountType);
42684281

42694282
// If that produces a pack type, expand the pattern element-wise.
42704283
if (auto substCountPackType = dyn_cast<PackType>(substCountType)) {
42714284
// Set up for element-wise expansion.
42724285
ActivePackExpansions.emplace_back(origCountType);
42734286

42744287
for (CanType substCountEltType : substCountPackType.getElementTypes()) {
4288+
auto expansionType = dyn_cast<PackExpansionType>(substCountEltType);
4289+
ActivePackExpansions.back().SubstPackExpansionCount =
4290+
(expansionType ? expansionType.getCountType() : CanType());
4291+
42754292
// Expand the pattern type in the element-wise context.
42764293
CanType expandedType = visit(origPatternType);
42774294

42784295
// Turn that into a pack expansion if appropriate for the
42794296
// count element.
4280-
if (auto expansionType =
4281-
dyn_cast<PackExpansionType>(substCountEltType)) {
4297+
if (expansionType) {
42824298
expandedType =
42834299
CanPackExpansionType::get(expandedType,
42844300
expansionType.getCountType());
@@ -4317,11 +4333,44 @@ class SILTypeSubstituter :
43174333
SmallVector<TupleTypeElt, 8> substElts;
43184334
substElts.reserve(origType->getNumElements());
43194335
for (auto &origElt : origType->getElements()) {
4320-
auto substEltType = visit(CanType(origElt.getType()));
4321-
substElts.push_back(origElt.getWithType(substEltType));
4336+
CanType origEltType = CanType(origElt.getType());
4337+
if (auto origExpansion = dyn_cast<PackExpansionType>(origEltType)) {
4338+
bool first = true;
4339+
substPackExpansion(origExpansion, [&](CanType substEltType) {
4340+
auto substElt = origElt.getWithType(substEltType);
4341+
if (first) {
4342+
first = false;
4343+
} else {
4344+
substElt = substElt.getWithoutName();
4345+
}
4346+
substElts.push_back(substElt);
4347+
});
4348+
} else {
4349+
auto substEltType = visit(origEltType);
4350+
substElts.push_back(origElt.getWithType(substEltType));
4351+
}
43224352
}
4353+
4354+
// Turn unlabeled singleton scalar tuples into their underlying types.
4355+
// The AST type substituter doesn't actually implement this rule yet,
4356+
// but we need to implement it in SIL in order to support testing,
4357+
// since the type parser can't parse a singleton tuple.
4358+
//
4359+
// For compatibility with previous behavior, don't do this if the
4360+
// original tuple type was singleton. AutoDiff apparently really
4361+
// likes making singleton tuples.
4362+
if (isParenType(substElts) && !isParenType(origType->getElements()))
4363+
return CanType(substElts[0].getType());
4364+
43234365
return CanType(TupleType::get(substElts, TC.Context));
43244366
}
4367+
4368+
static bool isParenType(ArrayRef<TupleTypeElt> elts) {
4369+
return (elts.size() == 1 &&
4370+
!elts[0].hasName() &&
4371+
!isa<PackExpansionType>(CanType(elts[0].getType())));
4372+
}
4373+
43254374
// Block storage types need to substitute their capture type by these same
43264375
// rules.
43274376
CanType visitSILBlockStorageType(CanSILBlockStorageType origType) {
@@ -4375,11 +4424,21 @@ class SILTypeSubstituter :
43754424
[&](SubstitutableType *origType) -> Type {
43764425
auto substType = Subst(origType);
43774426
if (!substType) return substType;
4378-
auto substPackType = substType->getAs<PackType>();
4427+
auto substPackType = dyn_cast<PackType>(substType->getCanonicalType());
43794428
if (!substPackType) return substType;
4380-
auto index = getPackExpansionIndex(CanType(origType));
4381-
if (!index) return substType;
4382-
return substPackType->getElementType(*index);
4429+
auto activeExpansion = getActivePackExpansion(CanType(origType));
4430+
if (!activeExpansion) return substType;
4431+
auto substEltType =
4432+
substPackType.getElementType(activeExpansion->Index);
4433+
auto substExpansion = dyn_cast<PackExpansionType>(substEltType);
4434+
assert((bool) substExpansion ==
4435+
(bool) activeExpansion->SubstPackExpansionCount);
4436+
if (substExpansion) {
4437+
assert(hasSameShape(substExpansion.getCountType(),
4438+
activeExpansion->SubstPackExpansionCount));
4439+
return substExpansion.getPatternType();
4440+
}
4441+
return substEltType;
43834442
},
43844443
[&](CanType dependentType,
43854444
Type conformingReplacementType,
@@ -4388,23 +4447,27 @@ class SILTypeSubstituter :
43884447
conformingReplacementType,
43894448
conformingProtocol);
43904449
if (!conformance || !conformance.isPack()) return conformance;
4391-
auto index = getPackExpansionIndex(dependentType);
4392-
if (!index) return conformance;
4450+
auto activeExpansion = getActivePackExpansion(dependentType);
4451+
if (!activeExpansion) return conformance;
43934452
auto pack = conformance.getPack();
4394-
return pack->getPatternConformances()[*index];
4453+
auto substEltConf =
4454+
pack->getPatternConformances()[activeExpansion->Index];
4455+
// There isn't currently a ProtocolConformanceExpansion that
4456+
// we would need to look through here.
4457+
return substEltConf;
43954458
},
43964459
substOptions)->getCanonicalType();
43974460
}
43984461

4399-
Optional<size_t> getPackExpansionIndex(CanType dependentType) {
4462+
PackExpansion *getActivePackExpansion(CanType dependentType) {
44004463
// We push new expansions onto the end of this vector, and we
44014464
// want to honor the innermost expansion, so we have to traverse
44024465
// in it reverse.
44034466
for (auto &entry : reverse(ActivePackExpansions)) {
4404-
if (hasSameShape(dependentType, entry.ExpandedShape))
4405-
return entry.Index;
4467+
if (hasSameShape(dependentType, entry.OrigShapeClass))
4468+
return &entry;
44064469
}
4407-
return None;
4470+
return nullptr;
44084471
}
44094472

44104473
bool hasSameShape(CanType lhs, CanType rhs) {

0 commit comments

Comments
 (0)