Skip to content

Commit 1703b93

Browse files
Merge pull request swiftlang#63424 from nate-chandler/variadic-generics/irgen/witness-table-packs
[IRGen] Emit witness table packs.
2 parents 4f3f73b + 210ef1f commit 1703b93

File tree

8 files changed

+328
-9
lines changed

8 files changed

+328
-9
lines changed

lib/IRGen/GenArchetype.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -260,6 +260,7 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
260260
/*request*/ MetadataState::Complete,
261261
nullptr).getMetadata();
262262

263+
IGF.setScopedLocalTypeData(archetype, localDataKind, wtable);
263264
return wtable;
264265
}
265266

lib/IRGen/GenPack.cpp

Lines changed: 227 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,9 +15,11 @@
1515
//===----------------------------------------------------------------------===//
1616

1717
#include "GenPack.h"
18+
#include "GenProto.h"
1819
#include "swift/AST/Decl.h"
1920
#include "swift/AST/GenericEnvironment.h"
2021
#include "swift/AST/IRGenOptions.h"
22+
#include "swift/AST/PackConformance.h"
2123
#include "swift/AST/Types.h"
2224
#include "swift/SIL/SILModule.h"
2325
#include "swift/SIL/SILType.h"
@@ -158,9 +160,6 @@ static Address emitFixedSizeMetadataPackRef(IRGenFunction &IGF,
158160
IGF.Builder.CreateStore(metadata, slot);
159161
}
160162

161-
pack = IGF.Builder.CreateConstArrayGEP(
162-
pack, 0, IGF.IGM.getPointerSize());
163-
164163
return pack;
165164
}
166165

@@ -359,15 +358,238 @@ irgen::emitTypeMetadataPackRef(IRGenFunction &IGF, CanPackType packType,
359358
return result;
360359

361360
auto pack = emitTypeMetadataPack(IGF, packType, request);
362-
auto *metadata = IGF.Builder.CreateConstArrayGEP(
363-
pack.getAddress(), 0, IGF.IGM.getPointerSize()).getAddress();
361+
auto *metadata = pack.getAddress().getAddress();
364362

365363
auto response = MetadataResponse::forComplete(metadata);
366364
IGF.setScopedLocalTypeMetadata(packType, response);
367365

368366
return response;
369367
}
370368

369+
static Address emitFixedSizeWitnessTablePack(IRGenFunction &IGF,
370+
CanPackType packType,
371+
PackConformance *packConformance) {
372+
assert(!packType->containsPackExpansionType());
373+
374+
unsigned elementCount = packType->getNumElements();
375+
auto allocType =
376+
llvm::ArrayType::get(IGF.IGM.WitnessTablePtrTy, elementCount);
377+
378+
auto pack = IGF.createAlloca(allocType, IGF.IGM.getPointerAlignment());
379+
IGF.Builder.CreateLifetimeStart(pack,
380+
IGF.IGM.getPointerSize() * elementCount);
381+
382+
for (unsigned i : indices(packType->getElementTypes())) {
383+
Address slot =
384+
IGF.Builder.CreateStructGEP(pack, i, IGF.IGM.getPointerSize());
385+
386+
auto conformance = packConformance->getPatternConformances()[i];
387+
auto *wtable =
388+
emitWitnessTableRef(IGF, packType.getElementType(i),
389+
/*srcMetadataCache=*/nullptr, conformance);
390+
391+
IGF.Builder.CreateStore(wtable, slot);
392+
}
393+
394+
return pack;
395+
}
396+
397+
static llvm::Value *emitPackExpansionElementWitnessTable(
398+
IRGenFunction &IGF, CanPackExpansionType expansionTy,
399+
ProtocolConformanceRef conformance, llvm::Value *index) {
400+
auto patternTy = expansionTy.getPatternType();
401+
402+
// Find all the pack archetypes appearing in the pattern type.
403+
SmallVector<Type, 2> patternPacks;
404+
patternTy->getTypeParameterPacks(patternPacks);
405+
406+
// Get the outer generic signature and environment.
407+
auto *genericEnv = cast<PackArchetypeType>(expansionTy.getCountType())
408+
->getGenericEnvironment();
409+
auto subMap = genericEnv->getForwardingSubstitutionMap();
410+
411+
auto genericSig = genericEnv->getGenericSignature().getCanonicalSignature();
412+
413+
// Create an opened element signature and environment.
414+
auto elementSig = IGF.IGM.Context.getOpenedElementSignature(
415+
genericSig, expansionTy.getCountType());
416+
auto *elementEnv = GenericEnvironment::forOpenedElement(
417+
elementSig, UUID::fromTime(), expansionTy.getCountType(), subMap);
418+
419+
// Open each pack archetype.
420+
for (auto patternPackType : patternPacks) {
421+
// Get the witness table for the pack archetype.
422+
auto patternPackArchetype =
423+
cast<PackArchetypeType>(patternPackType->getCanonicalType());
424+
for (auto *proto : patternPackArchetype->getConformsTo()) {
425+
auto conf = ProtocolConformanceRef(proto);
426+
auto patternPack = emitWitnessTableRef(
427+
IGF, patternPackArchetype, /*srcMetadataCache=*/nullptr, conf);
428+
429+
patternPack = IGF.Builder.CreatePointerCast(patternPack,
430+
IGF.IGM.WitnessTablePtrPtrTy);
431+
432+
Address patternPackAddress(patternPack, IGF.IGM.WitnessTablePtrTy,
433+
IGF.IGM.getPointerAlignment());
434+
435+
// Load the witness table pack element from the current source index.
436+
Address fromPtr(
437+
IGF.Builder.CreateInBoundsGEP(patternPackAddress.getElementType(),
438+
patternPackAddress.getAddress(), index),
439+
patternPackAddress.getElementType(),
440+
patternPackAddress.getAlignment());
441+
auto *wtable = IGF.Builder.CreateLoad(fromPtr);
442+
443+
// Bind the witness table pack element to the element archetype.
444+
auto elementArchetype = elementEnv->mapPackTypeIntoElementContext(
445+
patternPackArchetype->getInterfaceType());
446+
447+
IGF.setScopedLocalTypeData(
448+
CanType(elementArchetype),
449+
LocalTypeDataKind::forProtocolWitnessTable(conf), wtable);
450+
}
451+
}
452+
453+
// Replace pack archetypes with element archetypes in the pattern type.
454+
auto instantiatedPatternTy =
455+
elementEnv
456+
->mapPackTypeIntoElementContext(patternTy->mapTypeOutOfContext())
457+
->getCanonicalType();
458+
459+
// FIXME: Handle witness table packs for associatedtype's conformances.
460+
461+
// Emit the element witness table.
462+
auto *wtable = emitWitnessTableRef(IGF, instantiatedPatternTy,
463+
/*srcMetadataCache=*/nullptr, conformance);
464+
return wtable;
465+
}
466+
467+
static void emitExpansionWitnessTablePack(IRGenFunction &IGF, Address pack,
468+
CanPackExpansionType expansionTy,
469+
ProtocolConformanceRef conformance,
470+
llvm::Value *dynamicIndex,
471+
llvm::Value *dynamicLength) {
472+
auto *prev = IGF.Builder.GetInsertBlock();
473+
auto *check = IGF.createBasicBlock("pack-expansion-check");
474+
auto *loop = IGF.createBasicBlock("pack-expansion-loop");
475+
auto *rest = IGF.createBasicBlock("pack-expansion-rest");
476+
477+
IGF.Builder.CreateBr(check);
478+
IGF.Builder.emitBlock(check);
479+
480+
// An index into the source witness table pack.
481+
auto *phi = IGF.Builder.CreatePHI(IGF.IGM.SizeTy, 2);
482+
phi->addIncoming(llvm::ConstantInt::get(IGF.IGM.SizeTy, 0), prev);
483+
484+
// If we reach the end, jump to the continuation block.
485+
auto *cond = IGF.Builder.CreateICmpULT(phi, dynamicLength);
486+
IGF.Builder.CreateCondBr(cond, loop, rest);
487+
488+
IGF.Builder.emitBlock(loop);
489+
490+
auto *element =
491+
emitPackExpansionElementWitnessTable(IGF, expansionTy, conformance, phi);
492+
493+
// Store the element witness table into to the current destination index.
494+
auto *eltIndex = IGF.Builder.CreateAdd(dynamicIndex, phi);
495+
Address eltPtr(IGF.Builder.CreateInBoundsGEP(pack.getElementType(),
496+
pack.getAddress(), eltIndex),
497+
pack.getElementType(), pack.getAlignment());
498+
499+
IGF.Builder.CreateStore(element, eltPtr);
500+
501+
// Increment our counter.
502+
auto *next =
503+
IGF.Builder.CreateAdd(phi, llvm::ConstantInt::get(IGF.IGM.SizeTy, 1));
504+
505+
phi->addIncoming(next, loop);
506+
507+
// Repeat the loop.
508+
IGF.Builder.CreateBr(check);
509+
510+
// Fall through.
511+
IGF.Builder.emitBlock(rest);
512+
}
513+
514+
StackAddress irgen::emitWitnessTablePack(IRGenFunction &IGF,
515+
CanPackType packType,
516+
PackConformance *packConformance) {
517+
auto *shape = IGF.emitPackShapeExpression(packType);
518+
519+
if (auto *constantInt = dyn_cast<llvm::ConstantInt>(shape)) {
520+
assert(packType->getNumElements() == constantInt->getValue());
521+
return StackAddress(
522+
emitFixedSizeWitnessTablePack(IGF, packType, packConformance));
523+
}
524+
525+
assert(packType->containsPackExpansionType());
526+
auto pack = IGF.emitDynamicAlloca(IGF.IGM.WitnessTablePtrTy, shape,
527+
IGF.IGM.getPointerAlignment(),
528+
/*allowTaskAlloc=*/true);
529+
530+
auto index = 0;
531+
auto visitFn = [&](CanType eltTy, unsigned staticIndex,
532+
llvm::Value *dynamicIndex, llvm::Value *dynamicLength) {
533+
if (staticIndex != 0 || dynamicIndex == nullptr) {
534+
auto *constant = llvm::ConstantInt::get(IGF.IGM.SizeTy, staticIndex);
535+
accumulateSum(IGF, dynamicIndex, constant);
536+
}
537+
538+
auto conformance = packConformance->getPatternConformances()[index];
539+
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
540+
emitExpansionWitnessTablePack(IGF, pack.getAddress(), expansionTy,
541+
conformance, dynamicIndex, dynamicLength);
542+
} else {
543+
Address eltPtr(
544+
IGF.Builder.CreateInBoundsGEP(pack.getAddress().getElementType(),
545+
pack.getAddressPointer(), dynamicIndex),
546+
pack.getAddress().getElementType(), pack.getAlignment());
547+
548+
auto *wtable = emitWitnessTableRef(
549+
IGF, eltTy, /*srcMetadataCache=*/nullptr, conformance);
550+
IGF.Builder.CreateStore(wtable, eltPtr);
551+
}
552+
++index;
553+
};
554+
555+
visitPackExplosion(IGF, packType, visitFn);
556+
557+
return pack;
558+
}
559+
560+
void irgen::cleanupWitnessTablePack(IRGenFunction &IGF, StackAddress pack,
561+
Optional<unsigned> elementCount) {
562+
if (pack.getExtraInfo()) {
563+
IGF.emitDeallocateDynamicAlloca(pack);
564+
} else {
565+
IGF.Builder.CreateLifetimeEnd(pack.getAddress(),
566+
IGF.IGM.getPointerSize() * (*elementCount));
567+
}
568+
}
569+
570+
llvm::Value *irgen::emitWitnessTablePackRef(IRGenFunction &IGF,
571+
CanPackType packType,
572+
PackConformance *conformance) {
573+
assert(Lowering::TypeConverter::protocolRequiresWitnessTable(
574+
conformance->getProtocol()) &&
575+
"looking up witness table for protocol that doesn't have one");
576+
577+
auto localDataKind =
578+
LocalTypeDataKind::forProtocolWitnessTablePack(conformance);
579+
580+
auto wtable = IGF.tryGetLocalTypeData(packType, localDataKind);
581+
if (wtable)
582+
return wtable;
583+
584+
auto pack = emitWitnessTablePack(IGF, packType, conformance);
585+
586+
auto *result = pack.getAddress().getAddress();
587+
588+
IGF.setScopedLocalTypeData(packType, localDataKind, result);
589+
590+
return result;
591+
}
592+
371593
llvm::Value *
372594
irgen::emitTypeMetadataPackElementRef(IRGenFunction &IGF, CanPackType packType,
373595
llvm::Value *index,

lib/IRGen/GenPack.h

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,15 @@ void cleanupTypeMetadataPack(IRGenFunction &IGF,
5959
StackAddress pack,
6060
Optional<unsigned> elementCount);
6161

62+
StackAddress emitWitnessTablePack(IRGenFunction &IGF, CanPackType packType,
63+
PackConformance *conformance);
64+
65+
llvm::Value *emitWitnessTablePackRef(IRGenFunction &IGF, CanPackType packType,
66+
PackConformance *conformance);
67+
68+
void cleanupWitnessTablePack(IRGenFunction &IGF, StackAddress pack,
69+
Optional<unsigned> elementCount);
70+
6271
/// Emit the dynamic index of a particular structural component
6372
/// of the given pack type. If the component is a pack expansion, this
6473
/// is the index of the first element of the pack (or where it would be
@@ -78,4 +87,4 @@ Address emitStorageAddressOfPackElement(IRGenFunction &IGF,
7887
} // end namespace irgen
7988
} // end namespace swift
8089

81-
#endif
90+
#endif

lib/IRGen/GenProto.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -68,6 +68,7 @@
6868
#include "GenHeap.h"
6969
#include "GenMeta.h"
7070
#include "GenOpaque.h"
71+
#include "GenPack.h"
7172
#include "GenPointerAuth.h"
7273
#include "GenPoly.h"
7374
#include "GenType.h"
@@ -3250,6 +3251,9 @@ llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
32503251
// conformance info for them. However, that conformance info might be
32513252
// more concrete than we're expecting.
32523253
// TODO: make a best effort to devirtualize, maybe?
3254+
} else if (conformance.isPack()) {
3255+
auto pack = cast<PackType>(srcType);
3256+
return emitWitnessTablePackRef(IGF, pack, conformance.getPack());
32533257
} else {
32543258
concreteConformance = conformance.getConcrete();
32553259
}

lib/IRGen/LocalTypeData.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@
2525
#include "IRGenModule.h"
2626
#include "MetadataRequest.h"
2727
#include "swift/AST/IRGenOptions.h"
28+
#include "swift/AST/PackConformance.h"
2829
#include "swift/AST/ProtocolConformance.h"
2930
#include "swift/SIL/SILModule.h"
3031

@@ -705,12 +706,20 @@ void LocalTypeDataKind::print(llvm::raw_ostream &out) const {
705706
out << "AbstractConformance("
706707
<< getAbstractProtocolConformance()->getName()
707708
<< ")";
709+
} else if (isPackProtocolConformance()) {
710+
out << "PackConformance("
711+
<< getPackProtocolConformance()->getType()
712+
<< ":"
713+
<< getPackProtocolConformance()->getProtocol()->getName()
714+
<< ")";
708715
} else if (Value == FormalTypeMetadata) {
709716
out << "FormalTypeMetadata";
710717
} else if (Value == RepresentationTypeMetadata) {
711718
out << "RepresentationTypeMetadata";
712719
} else if (Value == ValueWitnessTable) {
713720
out << "ValueWitnessTable";
721+
} else if (Value == Shape) {
722+
out << "Shape";
714723
} else {
715724
assert(isSingletonKind());
716725
if (Value >= ValueWitnessDiscriminatorBase) {

lib/IRGen/LocalTypeDataKind.h

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -59,9 +59,10 @@ class LocalTypeDataKind {
5959
ValueWitnessDiscriminatorBase = ValueWitnessBase + MaxNumValueWitnesses,
6060

6161
FirstPayloadValue = 2048,
62-
Kind_Decl = 0,
63-
Kind_Conformance = 1,
64-
KindMask = 0x1,
62+
Kind_Decl = 0b0,
63+
Kind_Conformance = 0b1,
64+
Kind_PackConformance = 0b10,
65+
KindMask = 0b11,
6566
};
6667

6768
public:
@@ -119,10 +120,17 @@ class LocalTypeDataKind {
119120
return LocalTypeDataKind(uintptr_t(conformance) | Kind_Conformance);
120121
}
121122

123+
static LocalTypeDataKind forProtocolWitnessTablePack(PackConformance *pack) {
124+
assert(pack && "pack conformance reference may not be null");
125+
return LocalTypeDataKind(uintptr_t(pack) | Kind_PackConformance);
126+
}
127+
122128
static LocalTypeDataKind
123129
forProtocolWitnessTable(ProtocolConformanceRef conformance) {
124130
if (conformance.isConcrete()) {
125131
return forConcreteProtocolWitnessTable(conformance.getConcrete());
132+
} else if (conformance.isPack()) {
133+
return forProtocolWitnessTablePack(conformance.getPack());
126134
} else {
127135
return forAbstractProtocolWitnessTable(conformance.getAbstract());
128136
}
@@ -159,11 +167,24 @@ class LocalTypeDataKind {
159167
return reinterpret_cast<ProtocolDecl*>(Value - Kind_Decl);
160168
}
161169

170+
bool isPackProtocolConformance() const {
171+
return (!isSingletonKind() &&
172+
((Value & KindMask) == Kind_PackConformance));
173+
}
174+
175+
PackConformance *getPackProtocolConformance() const {
176+
assert(isPackProtocolConformance());
177+
return reinterpret_cast<PackConformance*>(Value - Kind_PackConformance);
178+
}
179+
162180
ProtocolConformanceRef getProtocolConformance() const {
163181
assert(!isSingletonKind());
164182
if ((Value & KindMask) == Kind_Decl) {
165183
return ProtocolConformanceRef(getAbstractProtocolConformance());
184+
} else if ((Value & KindMask) == Kind_PackConformance) {
185+
return ProtocolConformanceRef(getPackProtocolConformance());
166186
} else {
187+
assert((Value & KindMask) == Kind_Conformance);
167188
return ProtocolConformanceRef(getConcreteProtocolConformance());
168189
}
169190
}

0 commit comments

Comments
 (0)