Skip to content

Commit 7324307

Browse files
authored
Merge pull request #64073 from slavapestov/irgen-variadic-generic-types
Preliminary IRGen support for variadic generic types
2 parents 3cbff4e + 5e52ad5 commit 7324307

File tree

13 files changed

+469
-59
lines changed

13 files changed

+469
-59
lines changed

include/swift/AST/GenericSignature.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -432,6 +432,9 @@ class alignas(1 << TypeAlignInBits) GenericSignatureImpl final
432432
/// the same shape equivalence class.
433433
bool haveSameShape(Type type1, Type type2) const;
434434

435+
/// Returns all unique shape classes defined by this generic signature.
436+
SmallVector<CanType, 2> getShapeClasses() const;
437+
435438
/// Get the ordinal of a generic parameter in this generic signature.
436439
///
437440
/// For example, if you have a generic signature for a nested context like:

lib/AST/GenericSignature.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,19 @@ GenericSignatureImpl::haveSameShape(Type type1, Type type2) const {
544544
return getRequirementMachine()->haveSameShape(type1, type2);
545545
}
546546

547+
SmallVector<CanType, 2> GenericSignatureImpl::getShapeClasses() const {
548+
SmallSetVector<CanType, 2> result;
549+
550+
forEachParam([&](GenericTypeParamType *gp, bool canonical) {
551+
if (!canonical || !gp->isParameterPack())
552+
return;
553+
554+
result.insert(getReducedShape(gp)->getCanonicalType());
555+
});
556+
557+
return result.takeVector();
558+
}
559+
547560
unsigned GenericParamKey::findIndexIn(
548561
TypeArrayView<GenericTypeParamType> genericParams) const {
549562
// For depth 0, we have random access. We perform the extra checking so that

lib/IRGen/GenMeta.cpp

Lines changed: 99 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -414,6 +414,8 @@ namespace {
414414
unsigned NumParams = 0;
415415
unsigned NumRequirements = 0;
416416
unsigned NumGenericKeyArguments = 0;
417+
SmallVector<CanType, 2> ShapeClasses;
418+
SmallVector<GenericPackArgument, 2> GenericPackArguments;
417419

418420
GenericSignatureHeaderBuilder(IRGenModule &IGM,
419421
ConstantStructBuilder &builder)
@@ -422,13 +424,26 @@ namespace {
422424
NumGenericKeyArgumentsPP(builder.addPlaceholderWithSize(IGM.Int16Ty)),
423425
FlagsPP(builder.addPlaceholderWithSize(IGM.Int16Ty)) {}
424426

425-
void adjustAfterRequirements(const GenericRequirementsMetadata &info) {
427+
void add(const GenericArgumentMetadata &info) {
428+
ShapeClasses.append(info.ShapeClasses.begin(),
429+
info.ShapeClasses.end());
430+
426431
NumParams += info.NumParams;
427432
NumRequirements += info.NumRequirements;
433+
434+
for (auto pack : info.GenericPackArguments) {
435+
// Compute the final index.
436+
pack.Index += NumGenericKeyArguments + ShapeClasses.size();
437+
GenericPackArguments.push_back(pack);
438+
}
439+
428440
NumGenericKeyArguments += info.NumGenericKeyArguments;
429441
}
430442

431443
void finish(IRGenModule &IGM, ConstantStructBuilder &b) {
444+
assert(GenericPackArguments.empty() == ShapeClasses.empty() &&
445+
"Can't have one without the other");
446+
432447
assert(NumParams <= UINT16_MAX && "way too generic");
433448
b.fillPlaceholderWithInt(NumParamsPP, IGM.Int16Ty, NumParams);
434449

@@ -438,9 +453,9 @@ namespace {
438453

439454
assert(NumGenericKeyArguments <= UINT16_MAX && "way too generic");
440455
b.fillPlaceholderWithInt(NumGenericKeyArgumentsPP, IGM.Int16Ty,
441-
NumGenericKeyArguments);
456+
NumGenericKeyArguments + ShapeClasses.size());
442457

443-
bool hasTypePacks = false;
458+
bool hasTypePacks = !GenericPackArguments.empty();
444459
GenericContextDescriptorFlags flags(hasTypePacks);
445460
b.fillPlaceholderWithInt(FlagsPP, IGM.Int16Ty,
446461
flags.getIntValue());
@@ -495,6 +510,7 @@ namespace {
495510
asImpl().addGenericParametersHeader();
496511
asImpl().addGenericParameters();
497512
asImpl().addGenericRequirements();
513+
asImpl().addGenericPackShapeDescriptors();
498514
asImpl().finishGenericParameters();
499515
}
500516

@@ -512,7 +528,7 @@ namespace {
512528
/*implicit=*/false);
513529
assert(metadata.NumParams == metadata.NumParamsEmitted &&
514530
"We can't use implicit GenericParamDescriptors here");
515-
SignatureHeader->adjustAfterRequirements(metadata);
531+
SignatureHeader->add(metadata);
516532

517533
// Pad the structure up to four bytes for the following requirements.
518534
addPaddingAfterGenericParamDescriptors(IGM, B,
@@ -524,13 +540,49 @@ namespace {
524540
irgen::addGenericRequirements(IGM, B,
525541
asImpl().getGenericSignature(),
526542
asImpl().getGenericSignature().getRequirements());
527-
SignatureHeader->adjustAfterRequirements(metadata);
543+
SignatureHeader->add(metadata);
528544
}
529545

530546
void finishGenericParameters() {
531547
SignatureHeader->finish(IGM, B);
532548
}
533549

550+
void addGenericPackShapeDescriptors() {
551+
const auto &shapes = SignatureHeader->ShapeClasses;
552+
const auto &packArgs = SignatureHeader->GenericPackArguments;
553+
assert(shapes.empty() == packArgs.empty() &&
554+
"Can't have one without the other");
555+
556+
// If we don't have any pack arguments, there is nothing to emit.
557+
if (packArgs.empty())
558+
return;
559+
560+
// Emit the GenericPackShapeHeader first.
561+
562+
// NumPacks
563+
B.addInt(IGM.Int16Ty, packArgs.size());
564+
565+
// NumShapes
566+
B.addInt(IGM.Int16Ty, shapes.size());
567+
568+
// Emit each GenericPackShapeDescriptor collected previously.
569+
for (const auto &packArg : packArgs) {
570+
// Kind
571+
B.addInt(IGM.Int16Ty, uint16_t(packArg.Kind));
572+
573+
// Index
574+
B.addInt(IGM.Int16Ty, packArg.Index);
575+
576+
// ShapeClass
577+
auto found = std::find(shapes.begin(), shapes.end(), packArg.ReducedShape);
578+
assert(found != shapes.end());
579+
B.addInt(IGM.Int16Ty, found - shapes.begin());
580+
581+
// Unused
582+
B.addInt(IGM.Int16Ty, 0);
583+
}
584+
}
585+
534586
uint8_t getVersion() {
535587
return 0;
536588
}
@@ -6061,7 +6113,9 @@ void IRGenModule::emitProtocolDecl(ProtocolDecl *protocol) {
60616113

60626114
static GenericParamDescriptor
60636115
getGenericParamDescriptor(GenericTypeParamType *param, bool canonical) {
6064-
return GenericParamDescriptor(GenericParamKind::Type,
6116+
return GenericParamDescriptor(param->isParameterPack()
6117+
? GenericParamKind::TypePack
6118+
: GenericParamKind::Type,
60656119
/*key argument*/ canonical);
60666120
}
60676121

@@ -6077,13 +6131,13 @@ static bool canUseImplicitGenericParamDescriptors(CanGenericSignature sig) {
60776131
return allImplicit && count <= MaxNumImplicitGenericParamDescriptors;
60786132
}
60796133

6080-
GenericRequirementsMetadata
6134+
GenericArgumentMetadata
60816135
irgen::addGenericParameters(IRGenModule &IGM, ConstantStructBuilder &B,
60826136
GenericSignature sig, bool implicit) {
60836137
assert(sig);
60846138
auto canSig = sig.getCanonicalSignature();
60856139

6086-
GenericRequirementsMetadata metadata;
6140+
GenericArgumentMetadata metadata;
60876141

60886142
canSig->forEachParam([&](GenericTypeParamType *param, bool canonical) {
60896143
// Currently, there are only type parameters. The parameter is a key
@@ -6098,6 +6152,19 @@ irgen::addGenericParameters(IRGenModule &IGM, ConstantStructBuilder &B,
60986152

60996153
++metadata.NumParams;
61006154

6155+
// Only key arguments count toward NumGenericPackArguments.
6156+
if (descriptor.hasKeyArgument() &&
6157+
descriptor.getKind() == GenericParamKind::TypePack) {
6158+
auto reducedShape = canSig->getReducedShape(param)->getCanonicalType();
6159+
metadata.GenericPackArguments.emplace_back(
6160+
GenericPackKind::Metadata,
6161+
metadata.NumGenericKeyArguments,
6162+
reducedShape);
6163+
6164+
if (reducedShape->isEqual(param))
6165+
metadata.ShapeClasses.push_back(reducedShape);
6166+
}
6167+
61016168
if (descriptor.hasKeyArgument())
61026169
++metadata.NumGenericKeyArguments;
61036170
});
@@ -6121,11 +6188,21 @@ static void addRelativeAddressOfTypeRef(IRGenModule &IGM,
61216188

61226189
/// Add a generic requirement to the given constant struct builder.
61236190
static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
6124-
GenericRequirementsMetadata &metadata,
6191+
GenericArgumentMetadata &metadata,
61256192
GenericSignature sig,
61266193
GenericRequirementFlags flags,
61276194
Type paramType,
61286195
llvm::function_ref<void ()> addReference) {
6196+
// Only key arguments (ie, conformance requirements) count toward
6197+
// NumGenericPackArguments.
6198+
if (flags.hasKeyArgument() && flags.isPackRequirement()) {
6199+
assert(flags.getKind() == GenericRequirementKind::Protocol);
6200+
metadata.GenericPackArguments.emplace_back(
6201+
GenericPackKind::WitnessTable,
6202+
metadata.NumGenericKeyArguments,
6203+
sig->getReducedShape(paramType)->getCanonicalType());
6204+
}
6205+
61296206
if (flags.hasKeyArgument())
61306207
++metadata.NumGenericKeyArguments;
61316208

@@ -6134,13 +6211,13 @@ static void addGenericRequirement(IRGenModule &IGM, ConstantStructBuilder &B,
61346211
addReference();
61356212
}
61366213

6137-
GenericRequirementsMetadata irgen::addGenericRequirements(
6214+
GenericArgumentMetadata irgen::addGenericRequirements(
61386215
IRGenModule &IGM, ConstantStructBuilder &B,
61396216
GenericSignature sig,
61406217
ArrayRef<Requirement> requirements) {
61416218
assert(sig);
61426219

6143-
GenericRequirementsMetadata metadata;
6220+
GenericArgumentMetadata metadata;
61446221
for (auto &requirement : requirements) {
61456222
auto kind = requirement.getKind();
61466223
bool isPackRequirement = requirement.getFirstType()->isParameterPack();
@@ -6504,7 +6581,7 @@ irgen::emitExtendedExistentialTypeShape(IRGenModule &IGM,
65046581
GenericSignatureHeaderBuilder &header,
65056582
bool implicit) {
65066583
auto info = irgen::addGenericParameters(IGM, b, sig, implicit);
6507-
header.adjustAfterRequirements(info);
6584+
header.add(info);
65086585
totalParamDescriptors += info.NumParamsEmitted;
65096586
};
65106587
addParamDescriptors(reqSig, reqHeader, flags.hasImplicitReqSigParams());
@@ -6516,7 +6593,7 @@ irgen::emitExtendedExistentialTypeShape(IRGenModule &IGM,
65166593
auto addRequirementDescriptors = [&](CanGenericSignature sig,
65176594
GenericSignatureHeaderBuilder &header) {
65186595
auto info = addGenericRequirements(IGM, b, sig, sig.getRequirements());
6519-
header.adjustAfterRequirements(info);
6596+
header.add(info);
65206597
header.finish(IGM, b);
65216598
};
65226599

@@ -6526,6 +6603,15 @@ irgen::emitExtendedExistentialTypeShape(IRGenModule &IGM,
65266603
addRequirementDescriptors(genSig, *genHeader);
65276604
}
65286605

6606+
// The 'Self' parameter in an existential is not variadic
6607+
assert(reqHeader.GenericPackArguments.empty() &&
6608+
"Generic parameter packs should not ever appear here");
6609+
6610+
// You can have a superclass with a generic parameter pack in a composition,
6611+
// like `C<each T> & P<Int>`
6612+
assert(genHeader->GenericPackArguments.empty() &&
6613+
"Generic parameter packs not supported here yet");
6614+
65296615
return b.finishAndCreateFuture();
65306616
}, [&](llvm::GlobalVariable *var) {
65316617
var->setConstant(true);

lib/IRGen/GenMeta.h

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@
1717
#ifndef SWIFT_IRGEN_GENMETA_H
1818
#define SWIFT_IRGEN_GENMETA_H
1919

20+
#include "swift/ABI/MetadataValues.h"
2021
#include <utility>
2122

2223
namespace llvm {
@@ -169,18 +170,31 @@ namespace irgen {
169170
void getArgAsLocalSelfTypeMetadata(IRGenFunction &IGF, llvm::Value *arg,
170171
CanType abstractType);
171172

173+
struct GenericPackArgument {
174+
GenericPackKind Kind;
175+
unsigned Index;
176+
CanType ReducedShape;
177+
178+
GenericPackArgument(GenericPackKind kind,
179+
unsigned index,
180+
CanType reducedShape)
181+
: Kind(kind), Index(index), ReducedShape(reducedShape) {}
182+
};
183+
172184
/// Description of the metadata emitted by adding generic requirements.
173-
struct GenericRequirementsMetadata {
185+
struct GenericArgumentMetadata {
174186
unsigned NumParams = 0;
175187
unsigned NumParamsEmitted = 0;
176188
unsigned NumRequirements = 0;
177189
unsigned NumGenericKeyArguments = 0;
190+
SmallVector<CanType, 1> ShapeClasses;
191+
SmallVector<GenericPackArgument, 1> GenericPackArguments;
178192
};
179193

180194
/// Add generic parameters to the given constant struct builder.
181195
///
182196
/// \param sig The generic signature whose parameters we wish to emit.
183-
GenericRequirementsMetadata addGenericParameters(
197+
GenericArgumentMetadata addGenericParameters(
184198
IRGenModule &IGM,
185199
ConstantStructBuilder &B,
186200
GenericSignature sig,
@@ -192,7 +206,7 @@ namespace irgen {
192206
/// described.
193207
///
194208
/// \param requirements The requirements to add.
195-
GenericRequirementsMetadata addGenericRequirements(
209+
GenericArgumentMetadata addGenericRequirements(
196210
IRGenModule &IGM,
197211
ConstantStructBuilder &B,
198212
GenericSignature sig,

lib/IRGen/GenPack.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -458,6 +458,8 @@ irgen::emitTypeMetadataPackRef(IRGenFunction &IGF, CanPackType packType,
458458

459459
auto pack = emitTypeMetadataPack(IGF, packType, request);
460460
auto *metadata = pack.getAddress().getAddress();
461+
metadata = IGF.Builder.CreatePointerCast(
462+
metadata, IGF.IGM.TypeMetadataPtrTy->getPointerTo());
461463

462464
auto response = MetadataResponse::forComplete(metadata);
463465
IGF.setScopedLocalTypeMetadata(packType, response);
@@ -612,6 +614,8 @@ llvm::Value *irgen::emitWitnessTablePackRef(IRGenFunction &IGF,
612614
auto pack = emitWitnessTablePack(IGF, packType, conformance);
613615

614616
auto *result = pack.getAddress().getAddress();
617+
result = IGF.Builder.CreatePointerCast(
618+
result, IGF.IGM.WitnessTablePtrTy->getPointerTo());
615619

616620
IGF.setScopedLocalTypeData(packType, localDataKind, result);
617621

lib/IRGen/GenProto.cpp

Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -258,15 +258,7 @@ irgen::enumerateGenericSignatureRequirements(CanGenericSignature signature,
258258
const RequirementCallback &callback) {
259259
if (!signature) return;
260260

261-
// Get all unique pack generic parameter shapes.
262-
SmallSetVector<CanType, 2> packs;
263-
for (auto gp : signature.getGenericParams()) {
264-
if (gp->isParameterPack()) {
265-
packs.insert(signature->getReducedShape(gp)->getCanonicalType());
266-
}
267-
}
268-
269-
for (auto type : packs)
261+
for (auto type : signature->getShapeClasses())
270262
callback(GenericRequirement::forShape(type));
271263

272264
// Get all of the type metadata.
@@ -4087,6 +4079,8 @@ llvm::Constant *IRGenModule::getAddrOfGenericEnvironment(
40874079
irgen::addGenericParameters(*this, fields, signature, /*implicit=*/false);
40884080
assert(metadata.NumParamsEmitted == metadata.NumParams &&
40894081
"Implicit GenericParamDescriptors not supported here");
4082+
assert(metadata.GenericPackArguments.empty() &&
4083+
"We don't support packs here yet");
40904084

40914085
// Need to pad the structure after generic parameters
40924086
// up to four bytes because generic requirements that

lib/IRGen/MetadataRequest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1288,7 +1288,7 @@ static Address createGenericArgumentsArray(IRGenFunction &IGF,
12881288
for (unsigned i : indices(args)) {
12891289
Address elt = IGF.Builder.CreateStructGEP(argsBuffer, i,
12901290
IGF.IGM.getPointerSize() * i);
1291-
auto *arg = IGF.Builder.CreateBitCast(args[i], IGF.IGM.Int8PtrTy);
1291+
auto *arg = IGF.Builder.CreateBitOrPointerCast(args[i], IGF.IGM.Int8PtrTy);
12921292
IGF.Builder.CreateStore(arg, elt);
12931293
}
12941294

0 commit comments

Comments
 (0)