Skip to content

Commit 4be3c18

Browse files
authored
Merge pull request #64894 from rjmccall/vanishing-tuple-silgen-5.9
[5.9] SILGen and SIL type lowering for vanishing tuples
2 parents 9f9e709 + db0ecb3 commit 4be3c18

11 files changed

+312
-92
lines changed

include/swift/SIL/AbstractionPattern.h

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1283,8 +1283,9 @@ class AbstractionPattern {
12831283
}
12841284

12851285
/// Is the given tuple type a valid substitution of this abstraction
1286-
/// pattern?
1287-
bool matchesTuple(CanTupleType substType) const;
1286+
/// pattern? Note that the type doesn't have to be a tuple type in the
1287+
/// case of a vanishing tuple.
1288+
bool matchesTuple(CanType substType) const;
12881289

12891290
bool isTuple() const {
12901291
switch (getKind()) {
@@ -1344,6 +1345,14 @@ class AbstractionPattern {
13441345

13451346
bool doesTupleContainPackExpansionType() const;
13461347

1348+
/// If this type is a tuple type that vanishes (is flattened to its
1349+
/// singleton non-expansion element) under the stored substitutions,
1350+
/// return the abstraction pattern of the surviving element.
1351+
///
1352+
/// If the surviving element came from an expansion element, the
1353+
/// returned element is the pattern type of the expansion.
1354+
Optional<AbstractionPattern> getVanishingTupleElementPatternType() const;
1355+
13471356
static AbstractionPattern
13481357
projectTupleElementType(const AbstractionPattern *base, size_t index) {
13491358
return base->getTupleElementType(index);
@@ -1360,8 +1369,9 @@ class AbstractionPattern {
13601369
/// original type and how many elements of the substituted type they
13611370
/// expand to.
13621371
///
1363-
/// This pattern must be a tuple pattern.
1364-
void forEachTupleElement(CanTupleType substType,
1372+
/// This pattern must be a tuple pattern. The substituted type may be
1373+
/// a non-tuple only if this is a vanshing tuple pattern.
1374+
void forEachTupleElement(CanType substType,
13651375
llvm::function_ref<void(TupleElementGenerator &element)> fn) const;
13661376

13671377
/// Perform a parallel visitation of the elements of a tuple type,
@@ -1372,7 +1382,7 @@ class AbstractionPattern {
13721382
///
13731383
/// This pattern must match the substituted type, but it may be an
13741384
/// opaque pattern.
1375-
void forEachExpandedTupleElement(CanTupleType substType,
1385+
void forEachExpandedTupleElement(CanType substType,
13761386
llvm::function_ref<void(AbstractionPattern origEltType,
13771387
CanType substEltType,
13781388
const TupleTypeElt &elt)> handleElement) const;

include/swift/SIL/AbstractionPatternGenerators.h

Lines changed: 40 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,13 @@ class FunctionParamGenerator {
107107
/// to the current orig parameter.
108108
unsigned getSubstIndex() const {
109109
assert(!isFinished());
110-
return origParamIndex;
110+
return substParamIndex;
111+
}
112+
113+
IntRange<unsigned> getSubstIndexRange() const {
114+
assert(!isFinished());
115+
return IntRange<unsigned>(substParamIndex,
116+
substParamIndex + numSubstParamsForOrigParam);
111117
}
112118

113119
/// Return the parameter flags for the current orig parameter.
@@ -157,8 +163,9 @@ class TupleElementGenerator {
157163
/// during construction.
158164
AbstractionPattern origTupleType;
159165

160-
/// The substitute tuple type. Set once during construction.
161-
CanTupleType substTupleType;
166+
/// The substituted type. A tuple type unless this is a vanishing
167+
/// tuple. Set once during construction.
168+
CanType substType;
162169

163170
/// The number of orig elements to traverse. Set once during
164171
/// construction.
@@ -176,6 +183,10 @@ class TupleElementGenerator {
176183
/// orig element.
177184
unsigned numSubstEltsForOrigElt;
178185

186+
/// Whether the orig tuple type is a vanishing tuple, i.e. substitution
187+
/// turns it into a singleton element.
188+
bool origTupleVanishes;
189+
179190
/// Whether the orig tuple type is opaque, i.e. does not permit us to
180191
/// call getNumTupleElements() and similar accessors. Set once during
181192
/// construction.
@@ -189,6 +200,9 @@ class TupleElementGenerator {
189200
/// pattern type.
190201
AbstractionPattern origEltType = AbstractionPattern::getInvalid();
191202

203+
/// A scratch element that is used for vanishing tuple types.
204+
mutable TupleTypeElt scratchSubstElt;
205+
192206
/// Load the informaton for the current orig element into the
193207
/// fields above for it.
194208
void loadElement() {
@@ -202,7 +216,7 @@ class TupleElementGenerator {
202216

203217
public:
204218
TupleElementGenerator(AbstractionPattern origTupleType,
205-
CanTupleType substTupleType);
219+
CanType substType);
206220

207221
/// Is the traversal finished? If so, none of the getters below
208222
/// are allowed to be called.
@@ -228,14 +242,22 @@ class TupleElementGenerator {
228242
/// to the current orig element.
229243
unsigned getSubstIndex() const {
230244
assert(!isFinished());
231-
return origEltIndex;
245+
return substEltIndex;
246+
}
247+
248+
IntRange<unsigned> getSubstIndexRange() const {
249+
assert(!isFinished());
250+
return IntRange<unsigned>(substEltIndex,
251+
substEltIndex + numSubstEltsForOrigElt);
232252
}
233253

234254
/// Return a tuple element for the current orig element.
235255
TupleTypeElt getOrigElement() const {
236256
assert(!isFinished());
257+
// If the orig tuple is opaque, it can't have vanished, so this
258+
// cast of substType is okay.
237259
return (origTupleTypeIsOpaque
238-
? substTupleType->getElement(substEltIndex)
260+
? cast<TupleType>(substType)->getElement(substEltIndex)
239261
: cast<TupleType>(origTupleType.getType())
240262
->getElement(origEltIndex));
241263
}
@@ -257,15 +279,24 @@ class TupleElementGenerator {
257279
/// pack expansion, this will have exactly one element.
258280
CanTupleEltTypeArrayRef getSubstTypes() const {
259281
assert(!isFinished());
260-
return substTupleType.getElementTypes().slice(substEltIndex,
261-
numSubstEltsForOrigElt);
282+
if (!origTupleVanishes) {
283+
return cast<TupleType>(substType)
284+
.getElementTypes().slice(substEltIndex,
285+
numSubstEltsForOrigElt);
286+
} else if (numSubstEltsForOrigElt == 0) {
287+
return CanTupleEltTypeArrayRef();
288+
} else {
289+
scratchSubstElt = TupleTypeElt(substType);
290+
return CanTupleEltTypeArrayRef(scratchSubstElt);
291+
}
262292
}
263293

264294
/// Call this to finalize the traversal and assert that it was done
265295
/// properly.
266296
void finish() {
267297
assert(isFinished() && "didn't finish the traversal");
268-
assert(substEltIndex == substTupleType->getNumElements() &&
298+
assert(substEltIndex == (origTupleVanishes ? 1 :
299+
cast<TupleType>(substType)->getNumElements()) &&
269300
"didn't exhaust subst elements; possible missing subs on "
270301
"orig tuple type");
271302
}

lib/SIL/IR/AbstractionPattern.cpp

Lines changed: 90 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -283,7 +283,7 @@ LayoutConstraint AbstractionPattern::getLayoutConstraint() const {
283283
}
284284
}
285285

286-
bool AbstractionPattern::matchesTuple(CanTupleType substType) const {
286+
bool AbstractionPattern::matchesTuple(CanType substType) const {
287287
switch (getKind()) {
288288
case Kind::Invalid:
289289
llvm_unreachable("querying invalid abstraction pattern!");
@@ -311,11 +311,19 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) const {
311311
return false;
312312
LLVM_FALLTHROUGH;
313313
case Kind::Tuple: {
314+
if (getVanishingTupleElementPatternType()) {
315+
// TODO: recurse into elements.
316+
return true;
317+
}
318+
319+
auto substTupleType = dyn_cast<TupleType>(substType);
320+
if (!substTupleType) return false;
321+
314322
size_t nextSubstIndex = 0;
315323
auto nextComponentIsAcceptable = [&](bool isPackExpansion) -> bool {
316-
if (nextSubstIndex == substType->getNumElements())
324+
if (nextSubstIndex == substTupleType->getNumElements())
317325
return false;
318-
auto substComponentType = substType.getElementType(nextSubstIndex++);
326+
auto substComponentType = substTupleType.getElementType(nextSubstIndex++);
319327
return (isPackExpansion == isa<PackExpansionType>(substComponentType));
320328
};
321329
for (auto elt : getTupleElementTypes()) {
@@ -333,7 +341,7 @@ bool AbstractionPattern::matchesTuple(CanTupleType substType) const {
333341
return false;
334342
}
335343
}
336-
return nextSubstIndex == substType->getNumElements();
344+
return nextSubstIndex == substTupleType->getNumElements();
337345
}
338346
}
339347
llvm_unreachable("bad kind");
@@ -469,7 +477,63 @@ bool AbstractionPattern::doesTupleContainPackExpansionType() const {
469477
llvm_unreachable("bad kind");
470478
}
471479

472-
void AbstractionPattern::forEachTupleElement(CanTupleType substType,
480+
Optional<AbstractionPattern>
481+
AbstractionPattern::getVanishingTupleElementPatternType() const {
482+
if (!isTuple()) return None;
483+
if (!GenericSubs) return None;
484+
485+
// Substitution causes tuples to vanish when substituting the elements
486+
// produces a singleton tuple and it didn't start that way.
487+
488+
auto numOrigElts = getNumTupleElements();
489+
490+
// Track whether we've found a single element.
491+
Optional<AbstractionPattern> singletonEltType;
492+
bool hadOrigExpansion = false;
493+
for (auto index : range(numOrigElts)) {
494+
auto eltType = getTupleElementType(index);
495+
496+
// If this pattern isn't a pack expansion, we've got a new candidate
497+
// singleton. If this is the second such candidate, of course, it's
498+
// not a singleton.
499+
if (!eltType.isPackExpansion()) {
500+
if (singletonEltType) return None;
501+
singletonEltType = eltType;
502+
503+
// Otherwise, check what the expansion shape expands to.
504+
} else {
505+
hadOrigExpansion = true;
506+
507+
auto expansionType = cast<PackExpansionType>(eltType.getType());
508+
auto substShape = cast<PackType>(
509+
expansionType.getCountType().subst(GenericSubs)->getCanonicalType());
510+
auto expansionCount = substShape->getNumElements();
511+
512+
// If it expands to multiple elements or to a single expansion, we
513+
// won't have a singleton tuple. If it expands to a single scalar
514+
// element, this is a singleton candidate.
515+
if (expansionCount > 1) {
516+
return None;
517+
} else if (expansionCount == 1) {
518+
auto substExpansion =
519+
dyn_cast<PackExpansionType>(substShape.getElementType(0));
520+
if (substExpansion)
521+
return None;
522+
if (singletonEltType)
523+
return None;
524+
singletonEltType = eltType.getPackExpansionPatternType();
525+
}
526+
}
527+
}
528+
529+
// If we found a singleton scalar element, and we didn't start with
530+
// a singleton element, that's the index we want to return.
531+
if (singletonEltType && !(numOrigElts == 1 && !hadOrigExpansion))
532+
return singletonEltType;
533+
return None;
534+
}
535+
536+
void AbstractionPattern::forEachTupleElement(CanType substType,
473537
llvm::function_ref<void(TupleElementGenerator &)> handleElement) const {
474538
TupleElementGenerator elt(*this, substType);
475539
for (; !elt.isFinished(); elt.advance()) {
@@ -480,35 +544,46 @@ void AbstractionPattern::forEachTupleElement(CanTupleType substType,
480544

481545
TupleElementGenerator::TupleElementGenerator(
482546
AbstractionPattern origTupleType,
483-
CanTupleType substTupleType)
484-
: origTupleType(origTupleType), substTupleType(substTupleType) {
547+
CanType substType)
548+
: origTupleType(origTupleType), substType(substType) {
485549
assert(origTupleType.isTuple());
486-
assert(origTupleType.matchesTuple(substTupleType));
550+
assert(origTupleType.matchesTuple(substType));
487551

552+
origTupleVanishes =
553+
origTupleType.getVanishingTupleElementPatternType().hasValue();
488554
origTupleTypeIsOpaque = origTupleType.isOpaqueTuple();
489555
numOrigElts = origTupleType.getNumTupleElements();
490556

491557
if (!isFinished()) loadElement();
492558
}
493559

494-
void AbstractionPattern::forEachExpandedTupleElement(CanTupleType substType,
560+
void AbstractionPattern::forEachExpandedTupleElement(CanType substType,
495561
llvm::function_ref<void(AbstractionPattern origEltType,
496562
CanType substEltType,
497563
const TupleTypeElt &elt)>
498564
handleElement) const {
499565
assert(matchesTuple(substType));
500566

501-
auto substEltTypes = substType.getElementTypes();
502-
503567
// Handle opaque patterns by just iterating the substituted components.
504568
if (!isTuple()) {
569+
auto substTupleType = cast<TupleType>(substType);
570+
auto substEltTypes = substTupleType.getElementTypes();
505571
for (auto i : indices(substEltTypes)) {
506572
handleElement(getTupleElementType(i), substEltTypes[i],
507-
substType->getElement(i));
573+
substTupleType->getElement(i));
508574
}
509575
return;
510576
}
511577

578+
// For vanishing tuples, just call the callback once.
579+
if (auto origEltType = getVanishingTupleElementPatternType()) {
580+
handleElement(*origEltType, substType, TupleTypeElt(substType));
581+
return;
582+
}
583+
584+
auto substTupleType = cast<TupleType>(substType);
585+
auto substEltTypes = substTupleType.getElementTypes();
586+
512587
// For non-opaque patterns, we have to iterate the original components
513588
// in order to match things up properly, but we'll still end up calling
514589
// once per substituted element.
@@ -517,7 +592,7 @@ void AbstractionPattern::forEachExpandedTupleElement(CanTupleType substType,
517592
auto origEltType = getTupleElementType(origEltIndex);
518593
if (!origEltType.isPackExpansion()) {
519594
handleElement(origEltType, substEltTypes[substEltIndex],
520-
substType->getElement(substEltIndex));
595+
substTupleType->getElement(substEltIndex));
521596
substEltIndex++;
522597
} else {
523598
auto origPatternType = origEltType.getPackExpansionPatternType();
@@ -532,7 +607,8 @@ void AbstractionPattern::forEachExpandedTupleElement(CanTupleType substType,
532607
// be misleading in one way or another.
533608
handleElement(isa<PackExpansionType>(substEltType)
534609
? origEltType : origPatternType,
535-
substEltType, substType->getElement(substEltIndex));
610+
substEltType,
611+
substTupleType->getElement(substEltIndex));
536612
substEltIndex++;
537613
}
538614
}

lib/SIL/IR/SILFunctionType.cpp

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1270,8 +1270,7 @@ class DestructureResults {
12701270
void destructure(AbstractionPattern origType, CanType substType) {
12711271
// Recur into tuples.
12721272
if (origType.isTuple()) {
1273-
auto substTupleType = cast<TupleType>(substType);
1274-
origType.forEachTupleElement(substTupleType,
1273+
origType.forEachTupleElement(substType,
12751274
[&](TupleElementGenerator &elt) {
12761275
// If the original element type is not a pack expansion, just
12771276
// pull off the next substituted element type.
@@ -1646,7 +1645,7 @@ class DestructureInputs {
16461645

16471646
// Tuples get expanded unless they're inout.
16481647
if (origType.isTuple() && ownership != ValueOwnership::InOut) {
1649-
expandTuple(ownership, forSelf, origType, cast<TupleType>(substType),
1648+
expandTuple(ownership, forSelf, origType, substType,
16501649
isNonDifferentiable);
16511650
return;
16521651
}
@@ -1683,7 +1682,7 @@ class DestructureInputs {
16831682

16841683
/// Recursively expand a tuple type into separate parameters.
16851684
void expandTuple(ValueOwnership ownership, bool forSelf,
1686-
AbstractionPattern origType, CanTupleType substType,
1685+
AbstractionPattern origType, CanType substType,
16871686
bool isNonDifferentiable) {
16881687
assert(ownership != ValueOwnership::InOut);
16891688
assert(origType.isTuple());

0 commit comments

Comments
 (0)