Skip to content

Commit 57eeb18

Browse files
authored
Merge pull request #62548 from slavapestov/irgen-pack-shape
IRGen: Preliminary support for working with pack shapes
2 parents ebdee42 + 44fe0dc commit 57eeb18

25 files changed

+345
-255
lines changed

include/swift/AST/Types.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6054,6 +6054,8 @@ class PackArchetypeType final
60546054
return T->getKind() == TypeKind::PackArchetype;
60556055
}
60566056

6057+
CanTypeWrapper<PackType> getSingletonPackType();
6058+
60576059
private:
60586060
PackArchetypeType(const ASTContext &Ctx, GenericEnvironment *GenericEnv,
60596061
Type InterfaceType, ArrayRef<ProtocolDecl *> ConformsTo,

lib/AST/ASTDumper.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3948,6 +3948,7 @@ namespace {
39483948
printField("index", T->getIndex());
39493949
if (auto decl = T->getDecl())
39503950
printField("decl", decl->printRef());
3951+
printFlag(T->isParameterPack(), "pack");
39513952
PrintWithColorRAII(OS, ParenthesisColor) << ')';
39523953
}
39533954

lib/AST/ParameterPack.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -141,16 +141,11 @@ PackExpansionType *PackExpansionType::expand() {
141141
}
142142

143143
CanType PackExpansionType::getReducedShape() {
144-
if (auto *archetypeType = countType->getAs<PackArchetypeType>()) {
145-
auto shape = archetypeType->getReducedShape();
146-
return CanType(PackExpansionType::get(shape, shape));
147-
} else if (auto *packType = countType->getAs<PackType>()) {
148-
auto shape = packType->getReducedShape();
149-
return CanType(PackExpansionType::get(shape, shape));
150-
}
144+
auto reducedShape = countType->getReducedShape();
145+
if (reducedShape == getASTContext().TheEmptyTupleType)
146+
return reducedShape;
151147

152-
assert(countType->is<PlaceholderType>());
153-
return getASTContext().TheEmptyTupleType;
148+
return CanType(PackExpansionType::get(reducedShape, reducedShape));
154149
}
155150

156151
bool TupleType::containsPackExpansionType() const {
@@ -423,4 +418,10 @@ PackType *PackType::get(const ASTContext &C,
423418
}
424419

425420
return get(C, wrappedArgs)->flattenPackTypes();
426-
}
421+
}
422+
423+
CanPackType PackArchetypeType::getSingletonPackType() {
424+
SmallVector<Type, 1> types;
425+
types.push_back(PackExpansionType::get(this, getReducedShape()));
426+
return CanPackType(PackType::get(getASTContext(), types));
427+
}

lib/IRGen/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,7 @@ add_swift_host_library(swiftIRGen STATIC
3333
GenMeta.cpp
3434
GenObjC.cpp
3535
GenOpaque.cpp
36+
GenPack.cpp
3637
GenPointerAuth.cpp
3738
GenPoly.cpp
3839
GenProto.cpp

lib/IRGen/ClassMetadataVisitor.h

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -252,11 +252,7 @@ class ClassMetadataScanner : public ClassMetadataVisitor<Impl> {
252252
addPointer();
253253
}
254254
}
255-
void addGenericArgument(GenericRequirement requirement, ClassDecl *forClass) {
256-
addPointer();
257-
}
258-
void addGenericWitnessTable(GenericRequirement requirement,
259-
ClassDecl *forClass) {
255+
void addGenericRequirement(GenericRequirement requirement, ClassDecl *forClass) {
260256
addPointer();
261257
}
262258
void addPlaceholder(MissingMemberDecl *MMD) {

lib/IRGen/EnumMetadataVisitor.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -93,8 +93,7 @@ class EnumMetadataScanner : public EnumMetadataVisitor<Impl> {
9393
void addMetadataFlags() { addPointer(); }
9494
void addValueWitnessTable() { addPointer(); }
9595
void addNominalTypeDescriptor() { addPointer(); }
96-
void addGenericArgument(GenericRequirement requirement) { addPointer(); }
97-
void addGenericWitnessTable(GenericRequirement requirement) { addPointer(); }
96+
void addGenericRequirement(GenericRequirement requirement) { addPointer(); }
9897
void addPayloadSize() { addPointer(); }
9998
void noteStartOfTypeSpecificMembers() {}
10099
void addTrailingFlags() { addInt64(); }

lib/IRGen/Fulfillment.cpp

Lines changed: 36 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -279,38 +279,43 @@ bool FulfillmentMap::searchNominalTypeMetadata(IRGenModule &IGM,
279279

280280
bool hadFulfillment = false;
281281

282+
auto subs = type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal);
283+
282284
GenericTypeRequirements requirements(IGM, nominal);
283-
requirements.enumerateFulfillments(
284-
IGM, type->getContextSubstitutionMap(IGM.getSwiftModule(), nominal),
285-
[&](unsigned reqtIndex, CanType arg, ProtocolConformanceRef conf) {
286-
// Skip uninteresting type arguments.
287-
if (!keys.hasInterestingType(arg))
288-
return;
289-
290-
// If the fulfilled value is type metadata, refine the path.
291-
if (conf.isInvalid()) {
292-
auto argState =
293-
getPresumedMetadataStateForTypeArgument(metadataState);
294-
MetadataPath argPath = path;
295-
argPath.addNominalTypeArgumentComponent(reqtIndex);
296-
hadFulfillment |= searchTypeMetadata(
297-
IGM, arg, IsExact, argState, source, std::move(argPath), keys);
298-
return;
299-
}
300-
301-
// Otherwise, it's a conformance.
302-
303-
// Ignore it unless the type itself is interesting.
304-
if (!keys.isInterestingType(arg))
305-
return;
306-
307-
// Refine the path.
308-
MetadataPath argPath = path;
309-
argPath.addNominalTypeArgumentConformanceComponent(reqtIndex);
310-
311-
hadFulfillment |= searchWitnessTable(IGM, arg, conf.getRequirement(),
312-
source, std::move(argPath), keys);
313-
});
285+
286+
for (unsigned reqtIndex : indices(requirements.getRequirements())) {
287+
auto requirement = requirements.getRequirements()[reqtIndex];
288+
auto arg = requirement.getTypeParameter().subst(subs)->getCanonicalType();
289+
290+
// Skip uninteresting type arguments.
291+
if (!keys.hasInterestingType(arg))
292+
continue;
293+
294+
// If the fulfilled value is type metadata, refine the path.
295+
if (requirement.isMetadata()) {
296+
auto argState =
297+
getPresumedMetadataStateForTypeArgument(metadataState);
298+
MetadataPath argPath = path;
299+
argPath.addNominalTypeArgumentComponent(reqtIndex);
300+
hadFulfillment |= searchTypeMetadata(
301+
IGM, arg, IsExact, argState, source, std::move(argPath), keys);
302+
continue;
303+
}
304+
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);
315+
316+
hadFulfillment |= searchWitnessTable(IGM, arg, requirement.getProtocol(),
317+
source, std::move(argPath), keys);
318+
}
314319

315320
return hadFulfillment;
316321
}

lib/IRGen/GenDistributed.cpp

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -680,22 +680,21 @@ void DistributedAccessor::emit() {
680680
// We need this to determine the expected number of witness tables
681681
// to load from the buffer provided by the caller.
682682
llvm::SmallVector<llvm::Type *, 4> targetGenericArguments;
683-
auto numDirectGenericArgs =
683+
auto expandedSignature =
684684
expandPolymorphicSignature(IGM, targetTy, targetGenericArguments);
685+
assert(expandedSignature.numShapes == 0 &&
686+
"Distributed actors don't support variadic generics");
685687

686688
// Generic arguments associated with the distributed thunk directly
687689
// e.g. `distributed func echo<T, U>(...)`
688690
assert(
689691
!IGM.getLLVMContext().supportsTypedPointers() ||
690-
numDirectGenericArgs ==
692+
expandedSignature.numTypeMetadataPtrs ==
691693
llvm::count_if(targetGenericArguments, [&](const llvm::Type *type) {
692694
return type == IGM.TypeMetadataPtrTy;
693695
}));
694696

695-
auto expectedWitnessTables =
696-
targetGenericArguments.size() - numDirectGenericArgs;
697-
698-
for (unsigned index = 0; index < numDirectGenericArgs; ++index) {
697+
for (unsigned index = 0; index < expandedSignature.numTypeMetadataPtrs; ++index) {
699698
auto offset =
700699
Size(index * IGM.DataLayout.getTypeAllocSize(IGM.TypeMetadataPtrTy));
701700
auto alignment =
@@ -708,7 +707,7 @@ void DistributedAccessor::emit() {
708707
}
709708

710709
emitLoadOfWitnessTables(witnessTables, numWitnessTables,
711-
expectedWitnessTables, arguments);
710+
expandedSignature.numWitnessTablePtrs, arguments);
712711
}
713712

714713
// Step two, let's form and emit a call to the distributed method

lib/IRGen/GenMeta.cpp

Lines changed: 29 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -3851,13 +3851,8 @@ namespace {
38513851
llvm_unreachable("Fixed class metadata cannot have missing members");
38523852
}
38533853

3854-
void addGenericArgument(GenericRequirement requirement,
3855-
ClassDecl *forClass) {
3856-
llvm_unreachable("Fixed class metadata cannot have generic parameters");
3857-
}
3858-
3859-
void addGenericWitnessTable(GenericRequirement requirement,
3860-
ClassDecl *forClass) {
3854+
void addGenericRequirement(GenericRequirement requirement,
3855+
ClassDecl *forClass) {
38613856
llvm_unreachable("Fixed class metadata cannot have generic requirements");
38623857
}
38633858
};
@@ -3899,16 +3894,19 @@ namespace {
38993894
}
39003895
}
39013896

3902-
void addGenericArgument(GenericRequirement requirement,
3903-
ClassDecl *forClass) {
3904-
// Filled in at runtime.
3905-
B.addNullPointer(IGM.TypeMetadataPtrTy);
3906-
}
3907-
3908-
void addGenericWitnessTable(GenericRequirement requirement,
3909-
ClassDecl *forClass) {
3910-
// Filled in at runtime.
3911-
B.addNullPointer(IGM.WitnessTablePtrTy);
3897+
void addGenericRequirement(GenericRequirement requirement,
3898+
ClassDecl *forClass) {
3899+
switch (requirement.getKind()) {
3900+
case GenericRequirement::Kind::Shape:
3901+
B.addInt(IGM.SizeTy, 0);
3902+
break;
3903+
case GenericRequirement::Kind::Metadata:
3904+
B.addNullPointer(IGM.TypeMetadataPtrTy);
3905+
break;
3906+
case GenericRequirement::Kind::WitnessTable:
3907+
B.addNullPointer(IGM.WitnessTablePtrTy);
3908+
break;
3909+
}
39123910
}
39133911
};
39143912

@@ -4249,14 +4247,16 @@ namespace {
42494247
return emitValueWitnessTable(relativeReference);
42504248
}
42514249

4252-
void addGenericArgument(GenericRequirement requirement) {
4253-
auto t = requirement.getTypeParameter().subst(genericSubstitutions());
4254-
ConstantReference ref = IGM.getAddrOfTypeMetadata(
4255-
CanType(t), SymbolReferenceKind::Relative_Direct);
4256-
this->B.add(ref.getDirectValue());
4257-
}
4250+
void addGenericRequirement(GenericRequirement requirement) {
4251+
if (requirement.isMetadata()) {
4252+
auto t = requirement.getTypeParameter().subst(genericSubstitutions());
4253+
ConstantReference ref = IGM.getAddrOfTypeMetadata(
4254+
CanType(t), SymbolReferenceKind::Relative_Direct);
4255+
this->B.add(ref.getDirectValue());
4256+
return;
4257+
}
42584258

4259-
void addGenericWitnessTable(GenericRequirement requirement) {
4259+
assert(requirement.isWitnessTable());
42604260
auto conformance = genericSubstitutions().lookupConformance(
42614261
requirement.getTypeParameter()->getCanonicalType(),
42624262
requirement.getProtocol());
@@ -4334,14 +4334,9 @@ namespace {
43344334
const ClassLayout &fieldLayout)
43354335
: super(IGM, type, decl, B, fieldLayout), FieldLayout(fieldLayout) {}
43364336

4337-
void addGenericArgument(GenericRequirement requirement,
4338-
ClassDecl *theClass) {
4339-
super::addGenericArgument(requirement);
4340-
}
4341-
4342-
void addGenericWitnessTable(GenericRequirement requirement,
4343-
ClassDecl *theClass) {
4344-
super::addGenericWitnessTable(requirement);
4337+
void addGenericRequirement(GenericRequirement requirement,
4338+
ClassDecl *theClass) {
4339+
super::addGenericRequirement(requirement);
43454340
}
43464341

43474342
void addFieldOffsetPlaceholders(MissingMemberDecl *placeholder) {
@@ -4800,11 +4795,7 @@ namespace {
48004795
B.addAlignmentPadding(super::IGM.getPointerAlignment());
48014796
}
48024797

4803-
void addGenericArgument(GenericRequirement requirement) {
4804-
llvm_unreachable("Concrete type metadata cannot have generic parameters");
4805-
}
4806-
4807-
void addGenericWitnessTable(GenericRequirement requirement) {
4798+
void addGenericRequirement(GenericRequirement requirement) {
48084799
llvm_unreachable("Concrete type metadata cannot have generic requirements");
48094800
}
48104801

@@ -5169,11 +5160,7 @@ namespace {
51695160
PointerAuthEntity::Special::TypeDescriptor);
51705161
}
51715162

5172-
void addGenericArgument(GenericRequirement requirement) {
5173-
llvm_unreachable("Concrete type metadata cannot have generic parameters");
5174-
}
5175-
5176-
void addGenericWitnessTable(GenericRequirement requirement) {
5163+
void addGenericRequirement(GenericRequirement requirement) {
51775164
llvm_unreachable("Concrete type metadata cannot have generic requirements");
51785165
}
51795166

lib/IRGen/GenPack.cpp

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
//===--- GenPack.cpp - Swift IR Generation For Variadic Generics ----------===//
2+
//
3+
// This source file is part of the Swift.org open source project
4+
//
5+
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
6+
// Licensed under Apache License v2.0 with Runtime Library Exception
7+
//
8+
// See https://swift.org/LICENSE.txt for license information
9+
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
10+
//
11+
//===----------------------------------------------------------------------===//
12+
//
13+
// This file implements IR generation for type and value packs in Swift.
14+
//
15+
//===----------------------------------------------------------------------===//
16+
17+
#include "swift/AST/Decl.h"
18+
#include "swift/AST/IRGenOptions.h"
19+
#include "swift/AST/Types.h"
20+
#include "swift/SIL/SILModule.h"
21+
#include "swift/SIL/SILType.h"
22+
#include "llvm/IR/DerivedTypes.h"
23+
24+
#include "GenType.h"
25+
#include "IRGenFunction.h"
26+
#include "IRGenModule.h"
27+
28+
using namespace swift;
29+
using namespace irgen;
30+
31+
llvm::Value *IRGenFunction::emitPackShapeExpression(CanType type) {
32+
33+
type = type->getReducedShape()->getCanonicalType();
34+
35+
auto kind = LocalTypeDataKind::forPackShapeExpression();
36+
37+
llvm::Value *result = tryGetLocalTypeData(type, kind);
38+
if (result != nullptr)
39+
return result;
40+
41+
// If shape(T) == t and shape(U) == u, the shape expression for a pack
42+
// {T..., Int, T..., U..., String} becomes 't + t + u + 2'.
43+
unsigned scalarElements = 0;
44+
45+
auto accumulate = [&](llvm::Value *value) {
46+
if (result == nullptr) {
47+
result = value;
48+
return;
49+
}
50+
51+
result = Builder.CreateAdd(result, value);
52+
};
53+
54+
auto packType = cast<PackType>(type);
55+
for (auto elt : packType.getElementTypes()) {
56+
if (auto expansionType = dyn_cast<PackExpansionType>(elt)) {
57+
auto reducedShape = expansionType.getCountType();
58+
accumulate(emitPackShapeExpression(reducedShape));
59+
continue;
60+
}
61+
62+
++scalarElements;
63+
}
64+
65+
if (scalarElements > 0) {
66+
auto *constant = llvm::ConstantInt::get(IGM.SizeTy, scalarElements);
67+
accumulate(constant);
68+
}
69+
70+
setScopedLocalTypeData(type, kind, result);
71+
return result;
72+
}

0 commit comments

Comments
 (0)