Skip to content

Commit b2ffac5

Browse files
committed
IRGen: Fulfill pack metadata from tuple metadata
When the SelfMetadata in a witness thunk is the tuple type (repeat each Self), we can fulfill the pack shape and type metadata for Pack{repeat each Self} from tuple metadata. The length is trivially projected; the type metadata pack is slightly more involved, because tuple metadata stores a list of element/offset pairs, so we must stack allocate a pack and fill it in.
1 parent d09fd91 commit b2ffac5

File tree

8 files changed

+188
-9
lines changed

8 files changed

+188
-9
lines changed

lib/IRGen/Fulfillment.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,7 +173,33 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
173173
source, std::move(path), keys);
174174
}
175175

176-
// TODO: tuples
176+
if (auto tupleType = dyn_cast<TupleType>(type)) {
177+
if (tupleType->getNumElements() == 1 &&
178+
isa<PackExpansionType>(tupleType.getElementType(0))) {
179+
180+
bool hadFulfillment = false;
181+
auto packType = tupleType.getInducedPackType();
182+
183+
{
184+
auto argPath = path;
185+
argPath.addTuplePackComponent();
186+
hadFulfillment |= searchTypeMetadataPack(IGM, packType,
187+
isExact, metadataState, source,
188+
std::move(argPath), keys);
189+
}
190+
191+
{
192+
auto argPath = path;
193+
argPath.addTupleShapeComponent();
194+
hadFulfillment |= searchShapeRequirement(IGM, packType, source,
195+
std::move(argPath));
196+
197+
}
198+
199+
return hadFulfillment;
200+
}
201+
}
202+
177203
// TODO: functions
178204
// TODO: metatypes
179205

lib/IRGen/GenPack.cpp

Lines changed: 44 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1408,4 +1408,47 @@ irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
14081408
(void) visitPackExplosion(IGF, packType, visitFn);
14091409

14101410
return array;
1411-
}
1411+
}
1412+
1413+
std::pair<StackAddress, llvm::Value *>
1414+
irgen::emitInducedTupleTypeMetadataPack(
1415+
IRGenFunction &IGF, llvm::Value *tupleMetadata) {
1416+
auto *shape = emitTupleTypeMetadataLength(IGF, tupleMetadata);
1417+
1418+
auto pack = IGF.emitDynamicAlloca(IGF.IGM.TypeMetadataPtrTy, shape,
1419+
IGF.IGM.getPointerAlignment(),
1420+
/*allowTaskAlloc=*/true);
1421+
auto elementForIndex =
1422+
[&](llvm::Value *index) -> llvm::Value * {
1423+
return irgen::emitTupleTypeMetadataElementType(IGF, tupleMetadata, index);
1424+
};
1425+
1426+
auto *index = llvm::ConstantInt::get(IGF.IGM.SizeTy, 0);
1427+
emitPackExpansionPack(IGF, pack.getAddress(), index, shape,
1428+
elementForIndex);
1429+
1430+
IGF.recordStackPackMetadataAlloc(pack, shape);
1431+
1432+
return {pack, shape};
1433+
}
1434+
1435+
MetadataResponse
1436+
irgen::emitInducedTupleTypeMetadataPackRef(
1437+
IRGenFunction &IGF, CanPackType packType,
1438+
llvm::Value *tupleMetadata) {
1439+
StackAddress pack;
1440+
llvm::Value *shape;
1441+
std::tie(pack, shape) = emitInducedTupleTypeMetadataPack(
1442+
IGF, tupleMetadata);
1443+
1444+
auto *metadata = pack.getAddress().getAddress();
1445+
1446+
if (!IGF.canStackPromotePackMetadata()) {
1447+
metadata = IGF.Builder.CreateCall(
1448+
IGF.IGM.getAllocateMetadataPackFunctionPointer(), {metadata, shape});
1449+
1450+
cleanupTypeMetadataPack(IGF, pack, shape);
1451+
}
1452+
1453+
return MetadataResponse::forComplete(metadata);
1454+
}

lib/IRGen/GenPack.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,15 @@ emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
126126
CanPackType packType,
127127
llvm::Value *shapeExpression);
128128

129+
std::pair<StackAddress, llvm::Value *>
130+
emitInducedTupleTypeMetadataPack(
131+
IRGenFunction &IGF, llvm::Value *tupleMetadata);
132+
133+
MetadataResponse
134+
emitInducedTupleTypeMetadataPackRef(
135+
IRGenFunction &IGF, CanPackType packType,
136+
llvm::Value *tupleMetadata);
137+
129138
} // end namespace irgen
130139
} // end namespace swift
131140

lib/IRGen/GenProto.cpp

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@
7272
#include "GenPack.h"
7373
#include "GenPointerAuth.h"
7474
#include "GenPoly.h"
75+
#include "GenTuple.h"
7576
#include "GenType.h"
7677
#include "GenericRequirement.h"
7778
#include "IRGenDebugInfo.h"
@@ -3184,6 +3185,38 @@ MetadataResponse MetadataPath::followComponent(IRGenFunction &IGF,
31843185
return MetadataResponse::forComplete(capturedWTable);
31853186
}
31863187

3188+
case Component::Kind::TuplePack: {
3189+
assert(component.getPrimaryIndex() == 0);
3190+
3191+
auto tupleType = cast<TupleType>(sourceKey.Type);
3192+
auto packType = tupleType.getInducedPackType();
3193+
3194+
sourceKey.Kind = LocalTypeDataKind::forFormalTypeMetadata();
3195+
sourceKey.Type = packType;
3196+
3197+
if (!source) return MetadataResponse();
3198+
3199+
auto sourceMetadata = source.getMetadata();
3200+
return emitInducedTupleTypeMetadataPackRef(IGF, packType,
3201+
sourceMetadata);
3202+
}
3203+
3204+
case Component::Kind::TupleShape: {
3205+
assert(component.getPrimaryIndex() == 0);
3206+
3207+
auto tupleType = cast<TupleType>(sourceKey.Type);
3208+
3209+
sourceKey.Kind = LocalTypeDataKind::forPackShapeExpression();
3210+
sourceKey.Type = tupleType.getInducedPackType();
3211+
3212+
if (!source) return MetadataResponse();
3213+
3214+
auto sourceMetadata = source.getMetadata();
3215+
auto count = irgen::emitTupleTypeMetadataLength(IGF, sourceMetadata);
3216+
3217+
return MetadataResponse::forComplete(count);
3218+
}
3219+
31873220
case Component::Kind::Impossible:
31883221
llvm_unreachable("following an impossible path!");
31893222

@@ -3222,11 +3255,17 @@ void MetadataPath::print(llvm::raw_ostream &out) const {
32223255
out << "pack_expansion_count[" << component.getPrimaryIndex() << "]";
32233256
break;
32243257
case Component::Kind::PackExpansionPattern:
3225-
out << "pack_expansion_patttern[" << component.getPrimaryIndex() << "]";
3258+
out << "pack_expansion_pattern[" << component.getPrimaryIndex() << "]";
32263259
break;
32273260
case Component::Kind::ConditionalConformance:
32283261
out << "conditional_conformance[" << component.getPrimaryIndex() << "]";
32293262
break;
3263+
case Component::Kind::TuplePack:
3264+
out << "tuple_pack";
3265+
break;
3266+
case Component::Kind::TupleShape:
3267+
out << "tuple_shape";
3268+
break;
32303269
case Component::Kind::Impossible:
32313270
out << "impossible";
32323271
break;

lib/IRGen/GenTuple.cpp

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,4 +667,33 @@ llvm::Constant *irgen::getTupleLabelsString(IRGenModule &IGM,
667667
// Otherwise, create a new string literal.
668668
// This method implicitly adds a null terminator.
669669
return IGM.getAddrOfGlobalString(buffer);
670+
}
671+
672+
llvm::Value *irgen::emitTupleTypeMetadataLength(IRGenFunction &IGF,
673+
llvm::Value *metadata) {
674+
llvm::Value *indices[] = {
675+
IGF.IGM.getSize(Size(0)), // (*tupleType)
676+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 1) // .NumElements
677+
};
678+
auto slot = IGF.Builder.CreateInBoundsGEP(IGF.IGM.TupleTypeMetadataTy,
679+
metadata, indices);
680+
681+
return IGF.Builder.CreateLoad(slot, IGF.IGM.SizeTy,
682+
IGF.IGM.getPointerAlignment());
683+
}
684+
685+
llvm::Value *irgen::emitTupleTypeMetadataElementType(IRGenFunction &IGF,
686+
llvm::Value *metadata,
687+
llvm::Value *index) {
688+
llvm::Value *indices[] = {
689+
IGF.IGM.getSize(Size(0)), // (*tupleType)
690+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 3), // .Elements
691+
index, // [index]
692+
llvm::ConstantInt::get(IGF.IGM.Int32Ty, 0) // .Metadata
693+
};
694+
auto slot = IGF.Builder.CreateInBoundsGEP(IGF.IGM.TupleTypeMetadataTy,
695+
metadata, indices);
696+
697+
return IGF.Builder.CreateLoad(slot, IGF.IGM.SizeTy,
698+
IGF.IGM.getPointerAlignment());
670699
}

lib/IRGen/GenTuple.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,13 @@ namespace irgen {
7272
llvm::Constant *getTupleLabelsString(IRGenModule &IGM,
7373
CanTupleType type);
7474

75+
/// Load the NumElements of a tuple type metadata.
76+
llvm::Value *emitTupleTypeMetadataLength(IRGenFunction &IGF,
77+
llvm::Value *metadata);
78+
79+
llvm::Value *emitTupleTypeMetadataElementType(IRGenFunction &IGF,
80+
llvm::Value *metadata,
81+
llvm::Value *index);
7582
} // end namespace irgen
7683
} // end namespace swift
7784

lib/IRGen/MetadataPath.h

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,13 @@ class MetadataPath {
7373
/// The count type of a pack expansion at index P in a pack.
7474
PackExpansionCount,
7575

76-
LastWithPrimaryIndex = PackExpansionCount,
76+
/// Materialize tuple as a pack.
77+
TuplePack,
78+
79+
/// Materialize length of tuple as a pack shape expression.
80+
TupleShape,
81+
82+
LastWithPrimaryIndex = TupleShape,
7783

7884
// Everything past this point has no index.
7985

@@ -117,8 +123,10 @@ class MetadataPath {
117123
case Kind::NominalTypeArgumentShape:
118124
case Kind::NominalTypeArgument:
119125
case Kind::ConditionalConformance:
126+
case Kind::TupleShape:
120127
return OperationCost::Load;
121128

129+
case Kind::TuplePack:
122130
case Kind::AssociatedConformance:
123131
return OperationCost::Call;
124132

@@ -210,6 +218,14 @@ class MetadataPath {
210218
Path.push_back(Component(Component::Kind::PackExpansionCount, index));
211219
}
212220

221+
void addTuplePackComponent() {
222+
Path.push_back(Component(Component::Kind::TuplePack, /*index=*/0));
223+
}
224+
225+
void addTupleShapeComponent() {
226+
Path.push_back(Component(Component::Kind::TupleShape, /*index=*/0));
227+
}
228+
213229
/// Return an abstract measurement of the cost of this path.
214230
OperationCost cost() const {
215231
auto cost = OperationCost::Free;

test/IRGen/tuple_conformances.swift

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,27 +3,37 @@
33
import Swift
44

55
protocol P {
6-
func f()
6+
func defaultRequirement()
7+
static func staticRequirement()
78
}
89

910
extension P {
10-
func f() {}
11+
func defaultRequirement() {}
1112
}
1213

1314
extension Builtin.TheTupleType: P where repeat each Elements: P {
15+
static func staticRequirement() {}
1416
}
1517

1618
func takesP<T: P>(_ t: T) {
17-
t.f()
19+
t.defaultRequirement()
20+
T.staticRequirement()
1821
}
1922

20-
struct S: P {}
23+
struct S: P {
24+
static func staticRequirement() {
25+
print(self)
26+
}
27+
}
2128

2229
func use() {
30+
takesP(())
2331
takesP((S(), S()))
2432
}
2533

26-
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP1fyyFTW"({{i32|i64}} %0, ptr %"{{.*}}", ptr {{.*}} swiftself %1, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
34+
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP18defaultRequirementyyFTW"(ptr {{.*}} swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
35+
36+
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP17staticRequirementyyFZTW"(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
2737

2838
// CHECK-LABEL: define hidden swiftcc void @"$s18tuple_conformances3useyyF"() {{.*}} {
2939
// CHECK: call ptr @"$s18tuple_conformances1SV_ACtxxQp_tAA1PAAWl"()

0 commit comments

Comments
 (0)