Skip to content

Commit 7d779a9

Browse files
slavapestovrjmccall
authored andcommitted
IRGen: Fulfillment of pack shapes from nominal type metadata
1 parent a1c0abf commit 7d779a9

File tree

7 files changed

+131
-52
lines changed

7 files changed

+131
-52
lines changed

include/swift/IRGen/GenericRequirement.h

Lines changed: 20 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,10 +55,10 @@ class GenericRequirement {
5555
CanType type;
5656
ProtocolDecl *proto;
5757

58+
public:
5859
GenericRequirement(Kind kind, CanType type, ProtocolDecl *proto)
5960
: kind(kind), type(type), proto(proto) {}
6061

61-
public:
6262
Kind getKind() const {
6363
return kind;
6464
}
@@ -76,35 +76,34 @@ class GenericRequirement {
7676
}
7777

7878
static GenericRequirement forShape(CanType type) {
79-
assert(type->isParameterPack());
79+
assert(!isa<PackType>(type));
80+
assert(type->isParameterPack() || isa<PackArchetypeType>(type));
8081
return GenericRequirement(Kind::Shape, type, nullptr);
8182
}
8283

8384
bool isMetadata() const {
8485
return kind == Kind::Metadata || kind == Kind::MetadataPack;
8586
}
8687

87-
static GenericRequirement forMetadata(CanType type, bool isPack) {
88-
auto kind = isPack ? Kind::MetadataPack : Kind::Metadata;
89-
return GenericRequirement(kind, type, nullptr);
90-
}
91-
9288
static GenericRequirement forMetadata(CanType type) {
93-
return forMetadata(type, type->hasParameterPack());
89+
assert(!isa<PackType>(type));
90+
auto kind = ((type->isParameterPack() ||
91+
isa<PackArchetypeType>(type))
92+
? Kind::MetadataPack : Kind::Metadata);
93+
return GenericRequirement(kind, type, nullptr);
9494
}
9595

9696
bool isWitnessTable() const {
9797
return kind == Kind::WitnessTable || kind == Kind::WitnessTablePack;
9898
}
9999

100-
static GenericRequirement forWitnessTable(CanType type, ProtocolDecl *proto,
101-
bool isPack) {
102-
auto kind = isPack ? Kind::WitnessTablePack : Kind::WitnessTable;
103-
return GenericRequirement(kind, type, proto);
104-
}
105-
106100
static GenericRequirement forWitnessTable(CanType type, ProtocolDecl *proto) {
107-
return forWitnessTable(type, proto, type->hasParameterPack());
101+
assert(!isa<PackType>(type));
102+
auto kind = ((type->isParameterPack() ||
103+
isa<PackArchetypeType>(type))
104+
? Kind::WitnessTablePack
105+
: Kind::WitnessTable);
106+
return GenericRequirement(kind, type, proto);
108107
}
109108

110109
static llvm::Type *typeForKind(irgen::IRGenModule &IGM,
@@ -142,12 +141,14 @@ template <> struct DenseMapInfo<swift::GenericRequirement> {
142141
using GenericRequirement = swift::GenericRequirement;
143142
using CanTypeInfo = llvm::DenseMapInfo<swift::CanType>;
144143
static GenericRequirement getEmptyKey() {
145-
return GenericRequirement::forMetadata(CanTypeInfo::getEmptyKey(),
146-
/*isPack=*/false);
144+
return GenericRequirement(GenericRequirement::Kind::Metadata,
145+
CanTypeInfo::getEmptyKey(),
146+
nullptr);
147147
}
148148
static GenericRequirement getTombstoneKey() {
149-
return GenericRequirement::forMetadata(CanTypeInfo::getTombstoneKey(),
150-
/*isPack=*/false);
149+
return GenericRequirement(GenericRequirement::Kind::Metadata,
150+
CanTypeInfo::getTombstoneKey(),
151+
nullptr);
151152
}
152153
static llvm::hash_code getHashValue(GenericRequirement req) {
153154
return hash_combine(CanTypeInfo::getHashValue(req.getTypeParameter()),

lib/IRGen/Fulfillment.cpp

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -291,30 +291,44 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
291291
if (!keys.hasInterestingType(arg))
292292
continue;
293293

294-
// If the fulfilled value is type metadata, refine the path.
295-
if (requirement.isMetadata()) {
294+
switch (requirement.getKind()) {
295+
case GenericRequirement::Kind::Shape: {
296+
// If the fulfilled value is a shape class, refine the path.
297+
MetadataPath argPath = path;
298+
argPath.addNominalTypeArgumentShapeComponent(reqtIndex);
299+
300+
// Add the fulfillment.
301+
hadFulfillment |= addFulfillment(GenericRequirement::forShape(arg),
302+
source, std::move(argPath),
303+
MetadataState::Complete);
304+
break;
305+
}
306+
case GenericRequirement::Kind::Metadata:
307+
case GenericRequirement::Kind::MetadataPack: {
308+
// If the fulfilled value is type metadata, refine the path.
296309
auto argState =
297310
getPresumedMetadataStateForTypeArgument(metadataState);
298311
MetadataPath argPath = path;
299312
argPath.addNominalTypeArgumentComponent(reqtIndex);
300313
hadFulfillment |= searchTypeMetadata(
301314
IGM, arg, IsExact, argState, source, std::move(argPath), keys);
302-
continue;
315+
break;
303316
}
317+
case GenericRequirement::Kind::WitnessTable:
318+
case GenericRequirement::Kind::WitnessTablePack: {
319+
// Ignore it unless the type itself is interesting.
320+
if (!keys.isInterestingType(arg))
321+
continue;
304322

305-
// Otherwise, it's a conformance.
306-
assert(requirement.isWitnessTable());
307-
308-
// Ignore it unless the type itself is interesting.
309-
if (!keys.isInterestingType(arg))
310-
continue;
311-
312-
// Refine the path.
313-
MetadataPath argPath = path;
314-
argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);
323+
// Refine the path.
324+
MetadataPath argPath = path;
325+
argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);
315326

316-
hadFulfillment |= searchWitnessTable(IGM, arg, requirement.getProtocol(),
317-
source, std::move(argPath), keys);
327+
hadFulfillment |= searchWitnessTable(IGM, arg, requirement.getProtocol(),
328+
source, std::move(argPath), keys);
329+
break;
330+
}
331+
}
318332
}
319333

320334
return hadFulfillment;

lib/IRGen/GenMeta.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,15 @@ namespace irgen {
130130
unsigned reqtIndex,
131131
llvm::Value *metadata);
132132

133+
/// Given a reference to nominal type metadata of the given type,
134+
/// derive a reference to a the pack shape stored in the nth
135+
/// requirement slot. The type must have generic arguments.
136+
llvm::Value *emitArgumentPackShapeRef(IRGenFunction &IGF,
137+
NominalTypeDecl *theDecl,
138+
const GenericTypeRequirements &reqts,
139+
unsigned reqtIndex,
140+
llvm::Value *metadata);
141+
133142
/// Given a metatype value, read its instance type.
134143
llvm::Value *emitMetatypeInstanceType(IRGenFunction &IGF,
135144
llvm::Value *metatypeMetadata);

lib/IRGen/GenProto.cpp

Lines changed: 24 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2782,7 +2782,8 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
27822782
DynamicMetadataRequest request) {
27832783
switch (component.getKind()) {
27842784
case Component::Kind::NominalTypeArgument:
2785-
case Component::Kind::NominalTypeArgumentConformance: {
2785+
case Component::Kind::NominalTypeArgumentConformance:
2786+
case Component::Kind::NominalTypeArgumentShape: {
27862787
assert(sourceKey.Kind == LocalTypeDataKind::forFormalTypeMetadata());
27872788
auto type = sourceKey.Type;
27882789
if (auto archetypeTy = dyn_cast<ArchetypeType>(type))
@@ -2820,9 +2821,24 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
28202821
// Do a dynamic check if necessary to satisfy the request.
28212822
return emitCheckTypeMetadataState(IGF, request, response);
28222823

2824+
// If this is a shape class, load the value.
2825+
} else if (component.getKind() == Component::Kind::NominalTypeArgumentShape) {
2826+
assert(requirement.isShape() && "index mismatch!");
2827+
2828+
sourceKey.Kind = LocalTypeDataKind::forPackShapeExpression();
2829+
2830+
if (!source) return MetadataResponse();
2831+
2832+
auto sourceMetadata = source.getMetadata();
2833+
auto shape = emitArgumentPackShapeRef(IGF, nominal,
2834+
requirements, reqtIndex,
2835+
sourceMetadata);
2836+
2837+
return MetadataResponse::forComplete(shape);
2838+
28232839
// Otherwise, we need to switch sourceKey.Kind to the appropriate
28242840
// conformance kind.
2825-
} else {
2841+
} else if (component.getKind() == Component::Kind::NominalTypeArgumentConformance) {
28262842
assert(requirement.isWitnessTable() && "index mismatch!");
28272843
auto conformance = subs.lookupConformance(requirement.getTypeParameter(),
28282844
requirement.getProtocol());
@@ -2840,6 +2856,8 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
28402856

28412857
return MetadataResponse::forComplete(wtable);
28422858
}
2859+
2860+
llvm_unreachable("Bad component kind");
28432861
}
28442862

28452863
case Component::Kind::OutOfLineBaseProtocol: {
@@ -3062,6 +3080,10 @@ void MetadataPath::print(llvm::raw_ostream &out) const {
30623080
out << "nominal_type_argument_conformance["
30633081
<< component.getPrimaryIndex() << "]";
30643082
break;
3083+
case Component::Kind::NominalTypeArgumentShape:
3084+
out << "nominal_type_argument_shape["
3085+
<< component.getPrimaryIndex() << "]";
3086+
break;
30653087
case Component::Kind::ConditionalConformance:
30663088
out << "conditional_conformance[" << component.getPrimaryIndex() << "]";
30673089
break;

lib/IRGen/LocalTypeData.cpp

Lines changed: 25 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -545,22 +545,13 @@ addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments,
545545
CanType type = fulfillment.first.getTypeParameter();
546546
LocalTypeDataKind localDataKind;
547547

548-
// For now, ignore witness-table fulfillments when they're not for
549-
// archetypes.
550-
if (fulfillment.first.isWitnessTable()) {
551-
ProtocolDecl *protocol = fulfillment.first.getProtocol();
552-
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
553-
auto conformsTo = archetype->getConformsTo();
554-
auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol);
555-
if (it == conformsTo.end()) continue;
556-
localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it);
557-
} else {
558-
continue;
559-
}
560-
561-
} else {
562-
assert(fulfillment.first.isMetadata());
563-
548+
switch (fulfillment.first.getKind()) {
549+
case GenericRequirement::Kind::Shape: {
550+
localDataKind = LocalTypeDataKind::forPackShapeExpression();
551+
break;
552+
}
553+
case GenericRequirement::Kind::Metadata:
554+
case GenericRequirement::Kind::MetadataPack: {
564555
// Ignore type metadata fulfillments for non-dependent types that
565556
// we can produce very cheaply. We don't want to end up emitting
566557
// the type metadata for Int by chasing through N layers of metadata
@@ -571,6 +562,24 @@ addAbstractForFulfillments(IRGenFunction &IGF, FulfillmentMap &&fulfillments,
571562
}
572563

573564
localDataKind = LocalTypeDataKind::forFormalTypeMetadata();
565+
break;
566+
}
567+
case GenericRequirement::Kind::WitnessTable:
568+
case GenericRequirement::Kind::WitnessTablePack: {
569+
// For now, ignore witness-table fulfillments when they're not for
570+
// archetypes.
571+
ProtocolDecl *protocol = fulfillment.first.getProtocol();
572+
if (auto archetype = dyn_cast<ArchetypeType>(type)) {
573+
auto conformsTo = archetype->getConformsTo();
574+
auto it = std::find(conformsTo.begin(), conformsTo.end(), protocol);
575+
if (it == conformsTo.end()) continue;
576+
localDataKind = LocalTypeDataKind::forAbstractProtocolWitnessTable(*it);
577+
} else {
578+
continue;
579+
}
580+
581+
break;
582+
}
574583
}
575584

576585
// Find the chain for the key.

lib/IRGen/MetadataLayout.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -235,6 +235,19 @@ llvm::Value *irgen::emitArgumentWitnessTableRef(IRGenFunction &IGF,
235235
IGF.IGM.WitnessTablePtrTy);
236236
}
237237

238+
/// Given a reference to nominal type metadata of the given type,
239+
/// derive a reference to the pack shape for the nth argument
240+
/// metadata. The type must have generic arguments.
241+
llvm::Value *irgen::emitArgumentPackShapeRef(IRGenFunction &IGF,
242+
NominalTypeDecl *decl,
243+
const GenericTypeRequirements &reqts,
244+
unsigned reqtIndex,
245+
llvm::Value *metadata) {
246+
assert(reqts.getRequirements()[reqtIndex].isShape());
247+
return emitLoadOfGenericRequirement(IGF, metadata, decl, reqtIndex,
248+
IGF.IGM.SizeTy);
249+
}
250+
238251
Address irgen::emitAddressOfFieldOffsetVector(IRGenFunction &IGF,
239252
llvm::Value *metadata,
240253
NominalTypeDecl *decl) {

lib/IRGen/MetadataPath.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,9 @@ class MetadataPath {
5757
/// Witness table at requirement index P of a generic nominal type.
5858
NominalTypeArgumentConformance,
5959

60+
/// Pack length at requirement index P of a generic nominal type.
61+
NominalTypeArgumentShape,
62+
6063
/// Type metadata at requirement index P of a generic nominal type.
6164
NominalTypeArgument,
6265

@@ -104,6 +107,7 @@ class MetadataPath {
104107
switch (getKind()) {
105108
case Kind::OutOfLineBaseProtocol:
106109
case Kind::NominalTypeArgumentConformance:
110+
case Kind::NominalTypeArgumentShape:
107111
case Kind::NominalTypeArgument:
108112
case Kind::ConditionalConformance:
109113
return OperationCost::Load;
@@ -160,6 +164,13 @@ class MetadataPath {
160164
index));
161165
}
162166

167+
/// Add a step to this path which gets the pack length stored at
168+
/// requirement index n in a generic type metadata.
169+
void addNominalTypeArgumentShapeComponent(unsigned index) {
170+
Path.push_back(Component(Component::Kind::NominalTypeArgumentShape,
171+
index));
172+
}
173+
163174
/// Add a step to this path which gets the inherited protocol at
164175
/// a particular witness index.
165176
void addInheritedProtocolComponent(WitnessIndex index) {

0 commit comments

Comments
 (0)