Skip to content

Commit 68e1ba0

Browse files
authored
Merge pull request #68130 from slavapestov/irgen-fulfilling-tuple
IRGen: Fulfill pack metadata from tuple metadata
2 parents c17f686 + e45c0d4 commit 68e1ba0

File tree

9 files changed

+204
-25
lines changed

9 files changed

+204
-25
lines changed

include/swift/AST/Decl.h

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5937,6 +5937,14 @@ class VarDecl : public AbstractStorageDecl {
59375937
Bits.VarDecl.IsDebuggerVar = IsDebuggerVar;
59385938
}
59395939

5940+
/// Visit all auxiliary declarations to this VarDecl.
5941+
///
5942+
/// An auxiliary declaration is a declaration synthesized by the compiler to support
5943+
/// this VarDecl, such as synthesized property wrapper variables.
5944+
///
5945+
/// \note this function only visits auxiliary decls that are not part of the AST.
5946+
void visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)>) const;
5947+
59405948
/// Is this the synthesized storage for a 'lazy' property?
59415949
bool isLazyStorageProperty() const {
59425950
return Bits.VarDecl.IsLazyStorageProperty;
@@ -5945,6 +5953,9 @@ class VarDecl : public AbstractStorageDecl {
59455953
Bits.VarDecl.IsLazyStorageProperty = IsLazyStorage;
59465954
}
59475955

5956+
/// Retrieve the backing storage property for a lazy property.
5957+
VarDecl *getLazyStorageProperty() const;
5958+
59485959
/// True if this is a top-level global variable from the main source file.
59495960
bool isTopLevelGlobal() const { return Bits.VarDecl.IsTopLevelGlobal; }
59505961
void setTopLevelGlobal(bool b) { Bits.VarDecl.IsTopLevelGlobal = b; }
@@ -6052,17 +6063,6 @@ class VarDecl : public AbstractStorageDecl {
60526063
/// wrapper that has storage.
60536064
bool hasStorageOrWrapsStorage() const;
60546065

6055-
/// Visit all auxiliary declarations to this VarDecl.
6056-
///
6057-
/// An auxiliary declaration is a declaration synthesized by the compiler to support
6058-
/// this VarDecl, such as synthesized property wrapper variables.
6059-
///
6060-
/// \note this function only visits auxiliary decls that are not part of the AST.
6061-
void visitAuxiliaryDecls(llvm::function_ref<void(VarDecl *)>) const;
6062-
6063-
/// Retrieve the backing storage property for a lazy property.
6064-
VarDecl *getLazyStorageProperty() const;
6065-
60666066
/// Whether the memberwise initializer parameter for a property with a
60676067
/// property wrapper type uses the wrapped type. This will occur, for example,
60686068
/// when there is an explicitly-specified initializer like:

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: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -388,7 +388,7 @@ static llvm::Value *emitPackExpansionElementMetadata(
388388
/// dynamicLength) produced by the provided function \p elementForIndex into
389389
/// the indicated buffer \p pack.
390390
static void emitPackExpansionPack(
391-
IRGenFunction &IGF, Address pack, CanPackExpansionType expansionTy,
391+
IRGenFunction &IGF, Address pack,
392392
llvm::Value *dynamicIndex, llvm::Value *dynamicLength,
393393
function_ref<llvm::Value *(llvm::Value *)> elementForIndex) {
394394
auto *prev = IGF.Builder.GetInsertBlock();
@@ -442,7 +442,7 @@ static void emitPackExpansionMetadataPack(IRGenFunction &IGF, Address pack,
442442
llvm::Value *dynamicLength,
443443
DynamicMetadataRequest request) {
444444
emitPackExpansionPack(
445-
IGF, pack, expansionTy, dynamicIndex, dynamicLength, [&](auto *index) {
445+
IGF, pack, dynamicIndex, dynamicLength, [&](auto *index) {
446446
auto context =
447447
OpenedElementContext::createForContextualExpansion(IGF.IGM.Context, expansionTy);
448448
auto patternTy = expansionTy.getPatternType();
@@ -587,7 +587,7 @@ static void emitPackExpansionWitnessTablePack(
587587
ProtocolConformanceRef conformance, llvm::Value *dynamicIndex,
588588
llvm::Value *dynamicLength) {
589589
emitPackExpansionPack(
590-
IGF, pack, expansionTy, dynamicIndex, dynamicLength, [&](auto *index) {
590+
IGF, pack, dynamicIndex, dynamicLength, [&](auto *index) {
591591
llvm::Value *_metadata = nullptr;
592592
auto context =
593593
OpenedElementContext::createForContextualExpansion(IGF.IGM.Context, expansionTy);
@@ -1379,8 +1379,8 @@ irgen::emitDynamicFunctionParameterFlags(IRGenFunction &IGF,
13791379

13801380
// If we're looking at a pack expansion, insert the appropriate
13811381
// number of flags fields.
1382-
if (auto expansionTy = dyn_cast<PackExpansionType>(eltTy)) {
1383-
emitPackExpansionPack(IGF, array.getAddress(), expansionTy,
1382+
if (isa<PackExpansionType>(eltTy)) {
1383+
emitPackExpansionPack(IGF, array.getAddress(),
13841384
dynamicIndex, dynamicLength,
13851385
[&](llvm::Value *) -> llvm::Value * {
13861386
return flagsVal;
@@ -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
@@ -6,27 +6,37 @@
66
import Swift
77

88
protocol P {
9-
func f()
9+
func defaultRequirement()
10+
static func staticRequirement()
1011
}
1112

1213
extension P {
13-
func f() {}
14+
func defaultRequirement() {}
1415
}
1516

1617
extension Builtin.TheTupleType: P where repeat each Elements: P {
18+
static func staticRequirement() {}
1719
}
1820

1921
func takesP<T: P>(_ t: T) {
20-
t.f()
22+
t.defaultRequirement()
23+
T.staticRequirement()
2124
}
2225

23-
struct S: P {}
26+
struct S: P {
27+
static func staticRequirement() {
28+
print(self)
29+
}
30+
}
2431

2532
func use() {
33+
takesP(())
2634
takesP((S(), S()))
2735
}
2836

29-
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP1fyyFTW"({{i32|i64}} %0, ptr %"{{.*}}", ptr {{.*}} swiftself %1, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
37+
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP18defaultRequirementyyFTW"(ptr {{.*}} swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
38+
39+
// CHECK-LABEL: define internal swiftcc void @"$sxxQp_t18tuple_conformances1PA2aBP17staticRequirementyyFZTW"(ptr swiftself %0, ptr %Self, ptr %SelfWitnessTable) {{.*}} {
3040

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

0 commit comments

Comments
 (0)