Skip to content

Commit 989ea5b

Browse files
committed
[IRGen] Track repeated requirements for async functions in NecessaryBindings.
Previously, NecessaryBindings used a SetVector to store the GenericRequirements that it accumulates. That was a problem for the layout of async contexts where it is possible for the same generic argument to be repeated. Meanwhile, that is correct for partial application forwarders where there is a single thunk for every partial apply and consequently the bindings can be packed in without duplication. Here, a SetVector is used only when the NecessaryBindings are for partial apply forwarders. When the NecessaryBindings are instead for async functions, a SmallVector is used.
1 parent 506473d commit 989ea5b

File tree

2 files changed

+58
-30
lines changed

2 files changed

+58
-30
lines changed

lib/IRGen/GenProto.cpp

Lines changed: 15 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,21 +2688,21 @@ void irgen::emitPolymorphicParametersFromArray(IRGenFunction &IGF,
26882688

26892689
Size NecessaryBindings::getBufferSize(IRGenModule &IGM) const {
26902690
// We need one pointer for each archetype or witness table.
2691-
return IGM.getPointerSize() * Requirements.size();
2691+
return IGM.getPointerSize() * size();
26922692
}
26932693

26942694
void NecessaryBindings::restore(IRGenFunction &IGF, Address buffer,
26952695
MetadataState metadataState) const {
2696-
bindFromGenericRequirementsBuffer(IGF, Requirements.getArrayRef(), buffer,
2696+
bindFromGenericRequirementsBuffer(IGF, getRequirements(), buffer,
26972697
metadataState,
2698-
[&](CanType type) { return type;});
2698+
[&](CanType type) { return type; });
26992699
}
27002700

27012701
template <typename Transform>
27022702
static void save(const NecessaryBindings &bindings, IRGenFunction &IGF,
27032703
Address buffer, Transform transform) {
27042704
emitInitOfGenericRequirementsBuffer(
2705-
IGF, bindings.getRequirements().getArrayRef(), buffer,
2705+
IGF, bindings.getRequirements(), buffer,
27062706
[&](GenericRequirement requirement) -> llvm::Value * {
27072707
CanType type = requirement.TypeParameter;
27082708
if (auto protocol = requirement.Protocol) {
@@ -2770,14 +2770,13 @@ void NecessaryBindings::addTypeMetadata(CanType type) {
27702770
// Generic types are trickier, because they can require conformances.
27712771

27722772
// Otherwise, just record the need for this metadata.
2773-
Requirements.insert({type, nullptr});
2773+
addRequirement({type, nullptr});
27742774
}
27752775

27762776
/// Add all the abstract conditional conformances in the specialized
27772777
/// conformance to the \p requirements.
2778-
static void addAbstractConditionalRequirements(
2779-
SpecializedProtocolConformance *specializedConformance,
2780-
llvm::SetVector<GenericRequirement> &requirements) {
2778+
void NecessaryBindings::addAbstractConditionalRequirements(
2779+
SpecializedProtocolConformance *specializedConformance) {
27812780
auto subMap = specializedConformance->getSubstitutionMap();
27822781
auto condRequirements = specializedConformance->getConditionalRequirements();
27832782
for (auto req : condRequirements) {
@@ -2789,7 +2788,7 @@ static void addAbstractConditionalRequirements(
27892788
auto archetype = dyn_cast<ArchetypeType>(ty);
27902789
if (!archetype)
27912790
continue;
2792-
requirements.insert({ty, proto});
2791+
addRequirement({ty, proto});
27932792
}
27942793
// Recursively add conditional requirements.
27952794
for (auto &conf : subMap.getConformances()) {
@@ -2799,7 +2798,7 @@ static void addAbstractConditionalRequirements(
27992798
dyn_cast<SpecializedProtocolConformance>(conf.getConcrete());
28002799
if (!specializedConf)
28012800
continue;
2802-
addAbstractConditionalRequirements(specializedConf, requirements);
2801+
addAbstractConditionalRequirements(specializedConf);
28032802
}
28042803
}
28052804

@@ -2811,8 +2810,8 @@ void NecessaryBindings::addProtocolConformance(CanType type,
28112810
dyn_cast<SpecializedProtocolConformance>(concreteConformance);
28122811
// The partial apply forwarder does not have the context to reconstruct
28132812
// abstract conditional conformance requirements.
2814-
if (forPartialApply && specializedConf) {
2815-
addAbstractConditionalRequirements(specializedConf, Requirements);
2813+
if (forPartialApply() && specializedConf) {
2814+
addAbstractConditionalRequirements(specializedConf);
28162815
} else if (forAsyncFunction()) {
28172816
ProtocolDecl *protocol = conf.getRequirement();
28182817
GenericRequirement requirement;
@@ -2821,15 +2820,15 @@ void NecessaryBindings::addProtocolConformance(CanType type,
28212820
std::pair<GenericRequirement, ProtocolConformanceRef> pair{requirement,
28222821
conf};
28232822
Conformances.insert(pair);
2824-
Requirements.insert({type, concreteConformance->getProtocol()});
2823+
addRequirement({type, concreteConformance->getProtocol()});
28252824
}
28262825
return;
28272826
}
28282827
assert(isa<ArchetypeType>(type) || forAsyncFunction());
28292828

28302829
// TODO: pass something about the root conformance necessary to
28312830
// reconstruct this.
2832-
Requirements.insert({type, conf.getAbstract()});
2831+
addRequirement({type, conf.getAbstract()});
28332832
}
28342833

28352834
llvm::Value *irgen::emitWitnessTableRef(IRGenFunction &IGF,
@@ -3033,7 +3032,8 @@ NecessaryBindings NecessaryBindings::computeBindings(
30333032
bool forPartialApplyForwarder, bool considerParameterSources) {
30343033

30353034
NecessaryBindings bindings;
3036-
bindings.forPartialApply = forPartialApplyForwarder;
3035+
bindings.kind =
3036+
forPartialApplyForwarder ? Kind::PartialApply : Kind::AsyncFunction;
30373037

30383038
// Bail out early if we don't have polymorphic parameters.
30393039
if (!hasPolymorphicParameters(origType))

lib/IRGen/NecessaryBindings.h

Lines changed: 43 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,9 @@ namespace swift {
3232
enum class MetadataState : size_t;
3333
class ProtocolDecl;
3434
class ProtocolConformanceRef;
35+
class SpecializedProtocolConformance;
3536

36-
namespace irgen {
37+
namespace irgen {
3738
class Address;
3839
class IRGenFunction;
3940
class IRGenModule;
@@ -42,14 +43,32 @@ namespace irgen {
4243
/// NecessaryBindings - The set of metadata that must be saved in
4344
/// order to perform some set of operations on a type.
4445
class NecessaryBindings {
45-
llvm::SetVector<GenericRequirement> Requirements;
46+
enum class Kind {
47+
/// Are the bindings to be computed for a partial apply forwarder.
48+
/// In the case this is true we need to store/restore the conformance of a
49+
/// specialized type with conditional conformance because the conditional
50+
/// requirements are not available in the partial apply forwarder.
51+
PartialApply,
52+
AsyncFunction,
53+
};
54+
Kind kind;
55+
llvm::SetVector<GenericRequirement> RequirementsSet;
56+
llvm::SmallVector<GenericRequirement, 2> RequirementsVector;
4657
llvm::DenseMap<GenericRequirement, ProtocolConformanceRef> Conformances;
4758

48-
/// Are the bindings to be computed for a partial apply forwarder.
49-
/// In the case this is true we need to store/restore the conformance of a
50-
/// specialized type with conditional conformance because the conditional
51-
/// requirements are not available in the partial apply forwarder.
52-
bool forPartialApply = false;
59+
void addRequirement(GenericRequirement requirement) {
60+
switch (kind) {
61+
case Kind::PartialApply:
62+
RequirementsSet.insert(requirement);
63+
break;
64+
case Kind::AsyncFunction:
65+
RequirementsVector.push_back(requirement);
66+
break;
67+
}
68+
}
69+
70+
void addAbstractConditionalRequirements(
71+
SpecializedProtocolConformance *specializedConformance);
5372

5473
public:
5574
NecessaryBindings() = default;
@@ -70,24 +89,27 @@ class NecessaryBindings {
7089

7190
/// Get the requirement from the bindings at index i.
7291
const GenericRequirement &operator[](size_t i) const {
73-
return Requirements[i];
92+
switch (kind) {
93+
case Kind::PartialApply:
94+
return RequirementsSet[i];
95+
case Kind::AsyncFunction:
96+
return RequirementsVector[i];
97+
}
7498
}
7599

76100
ProtocolConformanceRef
77101
getConformance(const GenericRequirement &requirement) const {
78102
return Conformances.lookup(requirement);
79103
}
80104

81-
size_t size() const {
82-
return Requirements.size();
83-
}
105+
size_t size() const { return getRequirements().size(); }
84106

85107
/// Add whatever information is necessary to reconstruct a witness table
86108
/// reference for the given type.
87109
void addProtocolConformance(CanType type, ProtocolConformanceRef conf);
88110

89111
/// Is the work to do trivial?
90-
bool empty() const { return Requirements.empty(); }
112+
bool empty() const { return getRequirements().empty(); }
91113

92114
/// Returns the required size of the bindings.
93115
/// Pointer alignment is sufficient.
@@ -101,11 +123,17 @@ class NecessaryBindings {
101123
/// Restore the necessary bindings from the given buffer.
102124
void restore(IRGenFunction &IGF, Address buffer, MetadataState state) const;
103125

104-
const llvm::SetVector<GenericRequirement> &getRequirements() const {
105-
return Requirements;
126+
const llvm::ArrayRef<GenericRequirement> getRequirements() const {
127+
switch (kind) {
128+
case Kind::PartialApply:
129+
return RequirementsSet.getArrayRef();
130+
case Kind::AsyncFunction:
131+
return RequirementsVector;
132+
}
106133
}
107134

108-
bool forAsyncFunction() { return !forPartialApply; }
135+
bool forPartialApply() { return kind == Kind::PartialApply; }
136+
bool forAsyncFunction() { return kind == Kind::AsyncFunction; }
109137

110138
private:
111139
static NecessaryBindings computeBindings(IRGenModule &IGM,

0 commit comments

Comments
 (0)